001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.search;
029
030import org.opencms.configuration.CmsParameterConfiguration;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsPropertyDefinition;
033import org.opencms.file.CmsResource;
034import org.opencms.file.types.CmsResourceTypeXmlContainerPage;
035import org.opencms.file.types.CmsResourceTypeXmlContent;
036import org.opencms.i18n.CmsLocaleManager;
037import org.opencms.main.CmsException;
038import org.opencms.main.CmsIllegalArgumentException;
039import org.opencms.main.CmsLog;
040import org.opencms.main.OpenCms;
041import org.opencms.report.I_CmsReport;
042import org.opencms.search.documents.I_CmsDocumentFactory;
043import org.opencms.search.extractors.I_CmsExtractionResult;
044import org.opencms.search.fields.CmsSearchFieldConfiguration;
045import org.opencms.search.fields.I_CmsSearchFieldConfiguration;
046import org.opencms.search.solr.CmsSolrDocumentContainerPage;
047import org.opencms.search.solr.CmsSolrDocumentXmlContent;
048import org.opencms.util.CmsStringUtil;
049
050import java.io.IOException;
051import java.util.ArrayList;
052import java.util.Collections;
053import java.util.HashMap;
054import java.util.Iterator;
055import java.util.List;
056import java.util.Locale;
057import java.util.Map;
058import java.util.Objects;
059
060import org.apache.commons.logging.Log;
061
062/**
063 * Abstract base class for search indexes. It provides default implementations that should fit most use
064 * cases when adding own index implementations.
065 */
066public abstract class A_CmsSearchIndex implements I_CmsSearchIndex {
067
068    /** Special value for the search.exclude property. */
069    public static final String PROPERTY_SEARCH_EXCLUDE_VALUE_ALL = "all";
070
071    /** Special value for the search.exclude property. */
072    public static final String PROPERTY_SEARCH_EXCLUDE_VALUE_GALLERY = "gallery";
073
074    /** The use all locale. */
075    public static final String USE_ALL_LOCALE = "all";
076
077    /** The log object for this class. */
078    private static final Log LOG = CmsLog.getLog(A_CmsSearchIndex.class);
079
080    /** The serial version id. */
081    private static final long serialVersionUID = 5831386499514765251L;
082
083    /** Document types of folders/channels. */
084    private Map<String, List<String>> m_documenttypes;
085
086    /** An internal enabled flag, used to disable the index if for instance the configured project does not exist. */
087    private boolean m_enabled;
088
089    /** The content extraction mode for this index. */
090    private boolean m_extractContent;
091
092    /** The search field configuration of this index. */
093    private I_CmsSearchFieldConfiguration m_fieldConfiguration;
094
095    /** The name of the search field configuration used by this index. */
096    private String m_fieldConfigurationName;
097
098    /** The index writer to use. */
099    private transient I_CmsIndexWriter m_indexWriter;
100
101    /** Signals whether the language detection. */
102    private boolean m_languageDetection;
103
104    /** The locale of this index. */
105    private Locale m_locale;
106
107    /** The name of this index. */
108    private String m_name;
109
110    /** The path where this index stores it's data in the "real" file system. */
111    private String m_path;
112
113    /** The project of this index. */
114    private String m_project;
115
116    /** The rebuild mode for this index. */
117    private String m_rebuild;
118
119    /** The list of configured index source names. */
120    private List<String> m_sourceNames;
121
122    /** The list of configured index sources. */
123    private List<CmsSearchIndexSource> m_sources;
124
125    /**
126     * Default constructor only intended to be used by the XML configuration. <p>
127     *
128     * It is recommended to use the constructor <code>{@link #A_CmsSearchIndex(String)}</code>
129     * as it enforces the mandatory name argument. <p>
130     */
131    public A_CmsSearchIndex() {
132
133        m_sourceNames = new ArrayList<String>();
134        m_documenttypes = new HashMap<String, List<String>>();
135        m_enabled = true;
136        m_extractContent = true;
137    }
138
139    /**
140     * Creates a new CmsSearchIndex with the given name.<p>
141     *
142     * @param name the system-wide unique name for the search index
143     *
144     * @throws CmsIllegalArgumentException if the given name is null, empty or already taken by another search index
145     */
146    public A_CmsSearchIndex(String name)
147    throws CmsIllegalArgumentException {
148
149        this();
150        setName(name);
151    }
152
153    /**
154     * @see org.opencms.search.I_CmsSearchIndex#addConfigurationParameter(java.lang.String, java.lang.String)
155     */
156    public void addConfigurationParameter(String key, String value) {
157
158        // by default no parameters are excepted
159
160    }
161
162    /**
163     * Adds am index source to this search index.<p>
164     *
165     * @param sourceName the index source name to add
166     */
167    public void addSourceName(String sourceName) {
168
169        m_sourceNames.add(sourceName);
170    }
171
172    /**
173     * @see org.opencms.search.I_CmsSearchIndex#checkConfiguration(org.opencms.file.CmsObject)
174     */
175    public boolean checkConfiguration(CmsObject cms) {
176
177        if (isEnabled()) {
178            // check if the project for the index exists
179            try {
180                cms.readProject(getProject());
181                setEnabled(true);
182            } catch (CmsException e) {
183                // the project does not exist, disable the index
184                setEnabled(false);
185                if (LOG.isErrorEnabled()) {
186                    LOG.error(
187                        Messages.get().getBundle().key(
188                            Messages.LOG_SEARCHINDEX_CREATE_BAD_PROJECT_2,
189                            getProject(),
190                            getName()));
191                }
192            }
193        } else {
194            if (LOG.isInfoEnabled()) {
195                LOG.info(Messages.get().getBundle().key(Messages.LOG_SEARCHINDEX_DISABLED_1, getName()));
196            }
197        }
198
199        return isEnabled();
200    }
201
202    /**
203     * @see java.lang.Object#equals(java.lang.Object)
204     */
205    @Override
206    public boolean equals(Object obj) {
207
208        if (obj == this) {
209            return true;
210        }
211        if ((null != obj) && this.getClass().getName().equals(obj.getClass().getName())) {
212            return ((I_CmsSearchIndex)obj).getName().equals(m_name);
213        }
214        return false;
215    }
216
217    /**
218     * Checks if the provided resource should be excluded from this search index.<p>
219     *
220     * @param cms the OpenCms context used for building the search index
221     * @param resource the resource to index
222     *
223     * @return true if the resource should be excluded, false if it should be included in this index
224     */
225    public boolean excludeFromIndex(CmsObject cms, CmsResource resource) {
226
227        // check if this resource should be excluded from the index, if so skip it
228        boolean excludeFromIndex = false;
229
230        if (resource.isInternal()
231            || resource.isFolder()
232            || resource.isTemporaryFile()
233            || (resource.getDateExpired() <= System.currentTimeMillis())) {
234            // don't index internal resources, folders or temporary files or resources with expire date in the past
235            return true;
236        }
237
238        try {
239            // do property lookup with folder search
240            String propValue = cms.readPropertyObject(
241                resource,
242                CmsPropertyDefinition.PROPERTY_SEARCH_EXCLUDE,
243                true).getValue();
244            excludeFromIndex = Boolean.valueOf(propValue).booleanValue();
245            if (!excludeFromIndex && (propValue != null)) {
246                // property value was neither "true" nor null, must check for "all"
247                excludeFromIndex = PROPERTY_SEARCH_EXCLUDE_VALUE_ALL.equalsIgnoreCase(propValue.trim());
248            }
249        } catch (CmsException e) {
250            if (LOG.isDebugEnabled()) {
251                LOG.debug(
252                    Messages.get().getBundle().key(Messages.LOG_UNABLE_TO_READ_PROPERTY_1, resource.getRootPath()));
253            }
254        }
255        if (!excludeFromIndex && !USE_ALL_LOCALE.equalsIgnoreCase(getLocale().getLanguage())) {
256            // check if any resource default locale has a match with the index locale, if not skip resource
257            List<Locale> locales = OpenCms.getLocaleManager().getDefaultLocales(cms, resource);
258            Locale match = OpenCms.getLocaleManager().getFirstMatchingLocale(
259                Collections.singletonList(getLocale()),
260                locales);
261            excludeFromIndex = (match == null);
262        }
263
264        return excludeFromIndex;
265    }
266
267    /**
268     * Returns the empty configuration.
269     * Override the method if your index is configurable.
270     *
271     * @see org.opencms.search.I_CmsSearchIndex#getConfiguration()
272     */
273    public CmsParameterConfiguration getConfiguration() {
274
275        return new CmsParameterConfiguration();
276    }
277
278    /**
279     * We always assume we have no unchanged copy of the content, since it depends on the concrete index.
280     * Override the method to enhance indexing performance if you know where to grap the content from your index.
281     * See the implementation {@link org.opencms.search.CmsSearchIndex#getContentIfUnchanged(CmsResource)} for an example.
282     * @see org.opencms.search.I_CmsSearchIndex#getContentIfUnchanged(org.opencms.file.CmsResource)
283     */
284    public I_CmsExtractionResult getContentIfUnchanged(CmsResource resource) {
285
286        return null;
287    }
288
289    /**
290     * Returns the document type factory used for the given resource in this index, or <code>null</code>
291     * in case the resource is not indexed by this index.<p>
292     *
293     * A resource is indexed if the following is all true: <ol>
294     * <li>The index contains at last one index source matching the root path of the given resource.
295     * <li>For this matching index source, the document type factory needed by the resource is also configured.
296     * </ol>
297     *
298     * This default implementation uses the check as internal Solr indexes do. Overwrite it if necessary.
299     *
300     * @param res the resource to check
301     *
302     * @return the document type factory used for the given resource in this index, or <code>null</code>
303     * in case the resource is not indexed by this index
304     */
305    public I_CmsDocumentFactory getDocumentFactory(CmsResource res) {
306
307        if (isIndexing(res)) {
308            if (OpenCms.getResourceManager().getResourceType(res) instanceof CmsResourceTypeXmlContainerPage) {
309                return OpenCms.getSearchManager().getDocumentFactory(
310                    CmsSolrDocumentContainerPage.TYPE_CONTAINERPAGE_SOLR,
311                    "text/html");
312            }
313            if (CmsResourceTypeXmlContent.isXmlContent(res)) {
314                return OpenCms.getSearchManager().getDocumentFactory(
315                    CmsSolrDocumentXmlContent.TYPE_XMLCONTENT_SOLR,
316                    "text/html");
317            }
318            return OpenCms.getSearchManager().getDocumentFactory(res);
319        }
320        return null;
321    }
322
323    /**
324     * @see org.opencms.search.I_CmsSearchIndex#getFieldConfiguration()
325     */
326    public I_CmsSearchFieldConfiguration getFieldConfiguration() {
327
328        return m_fieldConfiguration;
329    }
330
331    /**
332     * @see org.opencms.search.I_CmsSearchIndex#getFieldConfigurationName()
333     */
334    public String getFieldConfigurationName() {
335
336        return m_fieldConfigurationName;
337    }
338
339    /**
340     * Returns a new index writer for this index.<p>
341     *
342     * @param report the report to write error messages on
343     * @param create if <code>true</code> a whole new index is created, if <code>false</code> an existing index is updated
344     *
345     * @return a new instance of IndexWriter
346     *
347     * @throws CmsIndexException if the index can not be opened
348     */
349    public I_CmsIndexWriter getIndexWriter(I_CmsReport report, boolean create) throws CmsIndexException {
350
351        // note - create will be:
352        //   true if the index is to be fully rebuild,
353        //   false if the index is to be incrementally updated
354        if (m_indexWriter != null) {
355            if (!create) {
356                // re-use existing index writer
357                return m_indexWriter;
358            }
359            // need to close the index writer if create is "true"
360            try {
361                m_indexWriter.close();
362                m_indexWriter = null;
363            } catch (IOException e) {
364                // if we can't close the index we are busted!
365                throw new CmsIndexException(
366                    Messages.get().container(Messages.LOG_IO_INDEX_WRITER_CLOSE_2, getPath(), getName()),
367                    e);
368            }
369
370        }
371
372        // now create is true of false, but the index writer is definitely null / closed
373        I_CmsIndexWriter indexWriter = createIndexWriter(create, report);
374
375        if (!create) {
376            m_indexWriter = indexWriter;
377        }
378
379        return indexWriter;
380    }
381
382    /**
383     * Returns the language locale of this index.<p>
384     *
385     * @return the language locale of this index, for example "en"
386     */
387    public Locale getLocale() {
388
389        return m_locale;
390    }
391
392    /**
393     * Returns the language locale for the given resource in this index.<p>
394     *
395     * @param cms the current OpenCms user context
396     * @param resource the resource to check
397     * @param availableLocales a list of locales supported by the resource
398     *
399     * @return the language locale for the given resource in this index
400     */
401    public Locale getLocaleForResource(CmsObject cms, CmsResource resource, List<Locale> availableLocales) {
402
403        Locale result = null;
404        List<Locale> defaultLocales = OpenCms.getLocaleManager().getDefaultLocales(cms, resource);
405        if ((availableLocales != null) && (availableLocales.size() > 0)) {
406            result = OpenCms.getLocaleManager().getBestMatchingLocale(
407                defaultLocales.get(0),
408                defaultLocales,
409                availableLocales);
410        }
411        if (result == null) {
412            result = ((availableLocales != null) && availableLocales.isEmpty())
413            ? availableLocales.get(0)
414            : defaultLocales.get(0);
415        }
416        return result;
417    }
418
419    /**
420     * @see org.opencms.search.I_CmsSearchIndex#getName()
421     */
422    public String getName() {
423
424        return m_name;
425    }
426
427    /**
428     * @see org.opencms.search.I_CmsSearchIndex#getPath()
429     */
430    public String getPath() {
431
432        return m_path;
433    }
434
435    /**
436     * @see org.opencms.search.I_CmsSearchIndex#getProject()
437     */
438    public String getProject() {
439
440        return m_project;
441    }
442
443    /**
444     * @see org.opencms.search.I_CmsSearchIndex#getRebuildMode()
445     */
446    public String getRebuildMode() {
447
448        return m_rebuild;
449    }
450
451    /**
452     * @see org.opencms.search.I_CmsSearchIndex#getSourceNames()
453     */
454    public List<String> getSourceNames() {
455
456        return m_sourceNames;
457    }
458
459    /**
460    * @see org.opencms.search.I_CmsSearchIndex#getSources()
461    */
462    public List<CmsSearchIndexSource> getSources() {
463
464        return m_sources;
465    }
466
467    /**
468     * @see java.lang.Object#hashCode()
469     */
470    @Override
471    public int hashCode() {
472
473        return m_name != null ? m_name.hashCode() : 0;
474    }
475
476    /**
477     * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#initConfiguration()
478     */
479    public void initConfiguration() {
480
481        // Do nothing by default
482
483    }
484
485    /**
486     * Initializes the search index.<p>
487     *
488     * @throws CmsSearchException if the index source association failed or a configuration error occurred
489     */
490
491    public void initialize() throws CmsSearchException {
492
493        if (!isEnabled()) {
494            // index is disabled, no initialization is required
495            return;
496        }
497
498        String sourceName = null;
499        CmsSearchIndexSource indexSource = null;
500        List<String> searchIndexSourceDocumentTypes = null;
501        List<String> resourceNames = null;
502        String resourceName = null;
503        m_sources = new ArrayList<CmsSearchIndexSource>();
504
505        m_path = getPath();
506
507        for (int i = 0, n = m_sourceNames.size(); i < n; i++) {
508
509            try {
510                sourceName = m_sourceNames.get(i);
511                indexSource = OpenCms.getSearchManager().getIndexSource(sourceName);
512                m_sources.add(indexSource);
513
514                resourceNames = indexSource.getResourcesNames();
515                searchIndexSourceDocumentTypes = indexSource.getDocumentTypes();
516                for (int j = 0, m = resourceNames.size(); j < m; j++) {
517
518                    resourceName = resourceNames.get(j);
519                    m_documenttypes.put(resourceName, searchIndexSourceDocumentTypes);
520                }
521            } catch (Exception e) {
522                // mark this index as disabled
523                setEnabled(false);
524                throw new CmsSearchException(
525                    Messages.get().container(Messages.ERR_INDEX_SOURCE_ASSOCIATION_1, sourceName),
526                    e);
527            }
528        }
529
530        // initialize the search field configuration
531        if (m_fieldConfigurationName == null) {
532            // if not set, use standard field configuration
533            m_fieldConfigurationName = CmsSearchFieldConfiguration.STR_STANDARD;
534        }
535        m_fieldConfiguration = OpenCms.getSearchManager().getFieldConfiguration(m_fieldConfigurationName);
536        if (m_fieldConfiguration == null) {
537            // we must have a valid field configuration to continue
538            throw new CmsSearchException(
539                Messages.get().container(Messages.ERR_FIELD_CONFIGURATION_UNKNOWN_2, m_name, m_fieldConfigurationName));
540        }
541
542        // initialize the index searcher instance
543        onIndexChanged(true);
544    }
545
546    /**
547     * @see org.opencms.search.I_CmsSearchIndex#isEnabled()
548     */
549    public boolean isEnabled() {
550
551        return m_enabled;
552    }
553
554    /**
555    * @see org.opencms.search.I_CmsSearchIndex#isExtractingContent()
556    */
557    public boolean isExtractingContent() {
558
559        return m_extractContent;
560    }
561
562    /**
563     * @see org.opencms.search.I_CmsSearchIndex#isInitialized()
564     */
565    public boolean isInitialized() {
566
567        return m_sources != null;
568    }
569
570    /**
571     * @see org.opencms.search.I_CmsSearchIndex#isLanguageDetection()
572     */
573    public boolean isLanguageDetection() {
574
575        return m_languageDetection;
576    }
577
578    /**
579     * Returns <code>true</code> in case this index is updated incremental.<p>
580     *
581     * An index is updated incremental if the index rebuild mode as defined by
582     * {@link #getRebuildMode()} is either set to {@value I_CmsSearchIndex#REBUILD_MODE_AUTO} or
583     * {@value I_CmsSearchIndex#REBUILD_MODE_OFFLINE}. Moreover, at least one update must have
584     * been written to the index already.
585     *
586     * @return <code>true</code> in case this index is updated incremental
587     */
588    public boolean isUpdatedIncremental() {
589
590        return m_indexWriter != null;
591    }
592
593    /**
594     * @see org.opencms.search.I_CmsSearchIndex#onIndexChanged(boolean)
595     */
596    public void onIndexChanged(boolean force) {
597
598        // Do nothing by default.
599
600    }
601
602    /**
603     * @see org.opencms.search.I_CmsSearchIndex#removeSourceName(String)
604     */
605    public void removeSourceName(String sourceName) {
606
607        Iterator<CmsSearchIndexSource> it = m_sources.iterator();
608        while (it.hasNext()) {
609            if (Objects.equals(it.next().getName(), sourceName)) {
610                it.remove();
611            }
612        }
613        m_sourceNames.remove(sourceName);
614    }
615
616    /**
617     * @see org.opencms.search.I_CmsSearchIndex#setEnabled(boolean)
618     */
619    public void setEnabled(boolean enabled) {
620
621        m_enabled = enabled;
622
623    }
624
625    /**
626     * Sets the field configuration used for this index.<p>
627     *
628     * @param fieldConfiguration the field configuration to set
629     */
630    public void setFieldConfiguration(I_CmsSearchFieldConfiguration fieldConfiguration) {
631
632        m_fieldConfiguration = fieldConfiguration;
633    }
634
635    /**
636     * Sets the name of the field configuration used for this index.<p>
637     *
638     * @param fieldConfigurationName the name of the field configuration to set
639     */
640    public void setFieldConfigurationName(String fieldConfigurationName) {
641
642        m_fieldConfigurationName = fieldConfigurationName;
643    }
644
645    /**
646     * Sets the languageDetection.<p>
647     *
648     * @param languageDetection the languageDetection to set
649     */
650    public void setLanguageDetection(boolean languageDetection) {
651
652        m_languageDetection = languageDetection;
653    }
654
655    /**
656     * @see org.opencms.search.I_CmsSearchIndex#setLocale(java.util.Locale)
657     */
658    public void setLocale(Locale locale) {
659
660        m_locale = locale;
661    }
662
663    /**
664     * @see org.opencms.search.I_CmsSearchIndex#setLocaleString(java.lang.String)
665     */
666    public void setLocaleString(String locale) {
667
668        setLocale(CmsLocaleManager.getLocale(locale));
669    }
670
671    /**
672    * @see org.opencms.search.I_CmsSearchIndex#setName(java.lang.String)
673    */
674    public void setName(String name) throws CmsIllegalArgumentException {
675
676        if (CmsStringUtil.isEmptyOrWhitespaceOnly(name)) {
677            throw new CmsIllegalArgumentException(
678                Messages.get().container(Messages.ERR_SEARCHINDEX_CREATE_MISSING_NAME_0));
679        } else {
680            // check if already used, but only if the name was modified:
681            // this is important as unmodifiable DisplayWidgets will also invoke this...
682            if (!name.equals(m_name)) {
683                // don't mess with XML configuration
684                if (OpenCms.getRunLevel() > OpenCms.RUNLEVEL_2_INITIALIZING) {
685                    // not needed at startup and additionally getSearchManager may return null
686                    Iterator<String> itIdxNames = OpenCms.getSearchManager().getIndexNames().iterator();
687                    while (itIdxNames.hasNext()) {
688                        if (itIdxNames.next().equals(name)) {
689                            throw new CmsIllegalArgumentException(
690                                Messages.get().container(Messages.ERR_SEARCHINDEX_CREATE_INVALID_NAME_1, name));
691                        }
692                    }
693                }
694            }
695        }
696        m_name = name;
697    }
698
699    /**
700     * Set the path to the index/core. This can either be the path to the directory where the
701     * index is stored or the URL where the index/core is reached.
702     * @param path to the index/core.
703     */
704    public void setPath(String path) {
705
706        m_path = path;
707    }
708
709    /**
710     * @see org.opencms.search.I_CmsSearchIndex#setProject(java.lang.String)
711     */
712    public void setProject(String project) {
713
714        m_project = project;
715    }
716
717    /**
718     * @see org.opencms.search.I_CmsSearchIndex#setRebuildMode(java.lang.String)
719     */
720    public void setRebuildMode(String rebuildMode) {
721
722        m_rebuild = rebuildMode;
723
724    }
725
726    /**
727     * @see org.opencms.search.I_CmsSearchIndex#shutDown()
728     */
729    public void shutDown() {
730
731        // close the index writer
732        if (m_indexWriter != null) {
733            try {
734                m_indexWriter.commit();
735                m_indexWriter.close();
736            } catch (IOException e) {
737                LOG.error(
738                    Messages.get().getBundle().key(Messages.LOG_IO_INDEX_WRITER_CLOSE_2, getPath(), getName()),
739                    e);
740            }
741        }
742    }
743
744    /**
745     * Creates a new index writer.<p>
746     *
747     * @param create if <code>true</code> a whole new index is created, if <code>false</code> an existing index is updated
748     * @param report the report
749     *
750     * @return the created new index writer
751     *
752     * @throws CmsIndexException in case the writer could not be created
753     *
754     * @see #getIndexWriter(I_CmsReport, boolean)
755     */
756    protected abstract I_CmsIndexWriter createIndexWriter(boolean create, I_CmsReport report) throws CmsIndexException;
757
758    /**
759     * Checks if the given resource should be indexed by this index or not.<p>
760     *
761     * @param res the resource candidate
762     *
763     * @return <code>true</code> if the given resource should be indexed or <code>false</code> if not
764     */
765    protected boolean isIndexing(CmsResource res) {
766
767        if ((res != null) && (getSources() != null)) {
768            I_CmsDocumentFactory result = OpenCms.getSearchManager().getDocumentFactory(res);
769            for (CmsSearchIndexSource source : getSources()) {
770                if (source.isIndexing(res.getRootPath(), CmsSolrDocumentContainerPage.TYPE_CONTAINERPAGE_SOLR)
771                    || source.isIndexing(res.getRootPath(), CmsSolrDocumentXmlContent.TYPE_XMLCONTENT_SOLR)
772                    || source.isIndexing(res.getRootPath(), result.getName())) {
773                    return true;
774                }
775            }
776        }
777        return false;
778    }
779
780    /**
781     * Sets a flag, indicating if the index should extract content.
782     * @param extract a flag, indicating if the index should extract content.
783     */
784    protected void setExtractContent(boolean extract) {
785
786        m_extractContent = extract;
787    }
788
789    /**
790     * Sets the index writer.<p>
791     *
792     * @param writer the index writer to set
793     */
794    protected void setIndexWriter(I_CmsIndexWriter writer) {
795
796        m_indexWriter = writer;
797    }
798
799}