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 GmbH & Co. KG, 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.main.CmsIllegalArgumentException;
031import org.opencms.main.CmsLog;
032import org.opencms.main.OpenCms;
033import org.opencms.search.documents.I_CmsDocumentFactory;
034import org.opencms.util.CmsStringUtil;
035
036import java.io.Serializable;
037import java.util.ArrayList;
038import java.util.HashMap;
039import java.util.Iterator;
040import java.util.LinkedHashMap;
041import java.util.List;
042import java.util.Map;
043
044import org.apache.commons.logging.Log;
045
046/**
047 * A search index source is a description of a list of Cms resources
048 * to be indexed.<p>
049 *
050 * @since 6.0.0
051 */
052public class CmsSearchIndexSource implements Comparable<CmsSearchIndexSource>, Serializable {
053
054    /** The serial version id. */
055    private static final long serialVersionUID = -3869627913906693823L;
056
057    /** The log object for this class. */
058    private static final Log LOG = CmsLog.getLog(CmsSearchIndexSource.class);
059
060    /** A list of Cms resource types to be indexed. */
061    private List<String> m_documentTypes;
062
063    /** The map from extraction keys to document factories. */
064    private transient Map<String, I_CmsDocumentFactory> m_documentFactories;
065
066    /** The indexer. */
067    private transient I_CmsIndexer m_indexer;
068
069    /** The class name of the indexer. */
070    private String m_indexerClassName;
071
072    /** The logical key/name of this index. */
073    private String m_name;
074
075    /** A map of optional key/value parameters. */
076    private Map<String, String> m_params;
077
078    /** A list of Cms resources to be indexed. */
079    private List<String> m_resourcesNames;
080
081    /**
082     * Creates a new CmsSearchIndexSource.<p>
083     */
084    public CmsSearchIndexSource() {
085
086        m_params = new HashMap<String, String>();
087        m_resourcesNames = new ArrayList<String>();
088        m_documentTypes = new ArrayList<String>();
089        m_documentFactories = new LinkedHashMap<>();
090    }
091
092    /**
093     * Adds a parameter.<p>
094     *
095     * @param key the key/name of the parameter
096     * @param value the value of the parameter
097     */
098    public void addConfigurationParameter(String key, String value) {
099
100        m_params.put(key, value);
101    }
102
103    /**
104     * Adds the name of a document type.<p>
105     *
106     * @param key the name of a document type to add
107     */
108    public void addDocumentType(String key) {
109
110        m_documentTypes.add(key);
111    }
112
113    /**
114     * Adds the path of a Cms resource.<p>
115     *
116     * @param resourceName the path of a Cms resource
117     */
118    public void addResourceName(String resourceName) {
119
120        m_resourcesNames.add(resourceName);
121    }
122
123    /**
124     * Returns <code>0</code> if the given object is an index source with the same name. <p>
125     *
126     * Note that the name of an index source has to be unique within OpenCms.<p>
127     *
128     * @param obj another index source
129     *
130     * @return <code>0</code> if the given object is an index source with the same name
131     *
132     * @see java.lang.Comparable#compareTo(java.lang.Object)
133     */
134    public int compareTo(CmsSearchIndexSource obj) {
135
136        if (obj == this) {
137            return 0;
138        }
139        return m_name.compareTo(obj.m_name);
140    }
141
142    /**
143     * Two index sources are considered equal if their names as returned by {@link #getName()} is equal.<p>
144     *
145     * Note that the name of an index source has to be unique within OpenCms.<p>
146     *
147     * @see java.lang.Object#equals(java.lang.Object)
148     */
149    @Override
150    public boolean equals(Object obj) {
151
152        if (obj == this) {
153            return true;
154        }
155        if (obj instanceof CmsSearchIndexSource) {
156            return m_name.equals(((CmsSearchIndexSource)obj).m_name);
157        }
158        return false;
159    }
160
161    /**
162     * Returns the document factory for given key.<p>
163     * Note that only the keys resulting from the document types for this source set are taken into account.<p>
164     *
165     * @param documentTypeKey the key for the factory to use.
166     * @return a document factory or null
167     */
168    public I_CmsDocumentFactory getDocumentFactory(String documentTypeKey) {
169
170        return null == documentTypeKey ? null : m_documentFactories.get(documentTypeKey);
171    }
172
173    /**
174     * Returns the list of names (Strings) of the document types to be indexed.<p>
175     *
176     * @return the list of names (Strings) of the document types to be indexed
177     */
178    public List<String> getDocumentTypes() {
179
180        return m_documentTypes;
181    }
182
183    /**
184     * Returns the indexer.<p>
185     *
186     * @return the indexer
187     */
188    public I_CmsIndexer getIndexer() {
189
190        return m_indexer;
191    }
192
193    /**
194     * Returns the class name of the indexer.<p>
195     *
196     * @return the class name of the indexer
197     */
198    public String getIndexerClassName() {
199
200        return m_indexerClassName;
201    }
202
203    /**
204     * Returns the logical key/name of this search index source.<p>
205     *
206     * @return the logical key/name of this search index source
207     */
208    public String getName() {
209
210        return m_name;
211    }
212
213    /**
214     * Returns the value for a specified parameter key.<p>
215     *
216     * @param key the parameter key/name
217     * @return the value for the specified parameter key
218     */
219    public String getParam(String key) {
220
221        return m_params.get(key);
222    }
223
224    /**
225     * Returns the map of optional key/value parameters.<p>
226     *
227     * @return the map of optional key/value parameters
228     */
229    public Map<String, String> getParams() {
230
231        return m_params;
232    }
233
234    /**
235     * Returns the list of VFS resources to be indexed.<p>
236     *
237     * @return the list of VFS resources to be indexed
238     */
239    public List<String> getResourcesNames() {
240
241        return m_resourcesNames;
242    }
243
244    /**
245     * Overriden to be consistents with overridden method
246     * <code>{@link #equals(Object)}</code>.
247     *
248     * @see java.lang.Object#hashCode()
249     */
250    @Override
251    public int hashCode() {
252
253        return m_name.hashCode();
254    }
255
256    /**
257     * Initialization for search index sources.
258     */
259    public void init() {
260
261        m_documentFactories = OpenCms.getSearchManager().getDocumentTypeMapForTypeNames(m_documentTypes);
262    }
263
264    /**
265     * Returns <code>true</code> in case the given resource root path is contained in the list of
266     * configured resource names of this index source.<p>
267     *
268     * @param rootPath the resource root path to check
269     *
270     * @return <code>true</code> in case the given resource root path is contained in the list of
271     *       configured resource names of this index source
272     *
273     * @see #getResourcesNames()
274     */
275    public boolean isContaining(String rootPath) {
276
277        if ((rootPath != null) && (m_resourcesNames != null)) {
278            Iterator<String> i = m_resourcesNames.iterator();
279            while (i.hasNext()) {
280                String path = i.next();
281                if (rootPath.startsWith(path)) {
282                    return true;
283                }
284            }
285        }
286        return false;
287    }
288
289    /**
290     * Returns <code>true</code> in case the given resource root path is contained in the list of
291     * configured resource names, and the given document type name is contained in the
292     * list if configured document type names of this index source.<p>
293     *
294     * @param rootPath the resource root path to check
295     * @param documentTypeKey the document type key for which the presence of a factory name has to be checked
296     *
297     * @return <code>true</code> in case the given resource root path is contained in the list of
298     *      configured resource names, and the given document type name is contained in the
299     *      list if configured document type names of this index source
300     *
301     * @see #isContaining(String)
302     * @see #getDocumentTypes()
303     */
304    public boolean isIndexing(String rootPath, String documentTypeKey) {
305
306        return m_documentFactories.keySet().contains(documentTypeKey) && isContaining(rootPath);
307    }
308
309    /**
310     * Removes the name of a document type from the list of configured types of this index source.<p>
311     *
312     * @param key the name of the document type to remove
313     *
314     * @return true if the given document type name was contained before thus could be removed successfully, false otherwise
315     */
316    public boolean removeDocumentType(String key) {
317
318        return m_documentTypes.remove(key);
319    }
320
321    /**
322     * Sets the list of document type names (Strings) to be indexed.<p>
323     *
324     * @param documentTypes the list of document type names (Strings) to be indexed
325     */
326    public void setDocumentTypes(List<String> documentTypes) {
327
328        m_documentTypes = documentTypes;
329    }
330
331    /**
332     * Sets the class name of the indexer.<p>
333     *
334     * An Exception is thrown to allow GUI-display of wrong input.<p>
335     *
336     * @param indexerClassName the class name of the indexer
337     *
338     * @throws CmsIllegalArgumentException if the given String is not a fully qualified classname (within this Java VM)
339     */
340    public void setIndexerClassName(String indexerClassName) throws CmsIllegalArgumentException {
341
342        try {
343            m_indexer = (I_CmsIndexer)Class.forName(indexerClassName).newInstance();
344            m_indexerClassName = indexerClassName;
345        } catch (Exception exc) {
346            if (LOG.isWarnEnabled()) {
347                LOG.warn(
348                    Messages.get().getBundle().key(Messages.LOG_INDEXER_CREATION_FAILED_1, m_indexerClassName),
349                    exc);
350            }
351            throw new CmsIllegalArgumentException(
352                Messages.get().container(
353                    Messages.ERR_INDEXSOURCE_INDEXER_CLASS_NAME_2,
354                    indexerClassName,
355                    I_CmsIndexer.class.getName()));
356        }
357    }
358
359    /**
360     * Sets the logical key/name of this search index source.<p>
361     *
362     * @param name the logical key/name of this search index source
363     *
364     * @throws CmsIllegalArgumentException if argument name is null, an empty or whitespace-only Strings
365     *         or already used for another indexsource's name.
366     */
367    public void setName(String name) throws CmsIllegalArgumentException {
368
369        if (CmsStringUtil.isEmptyOrWhitespaceOnly(name)) {
370            throw new CmsIllegalArgumentException(
371                Messages.get().container(Messages.ERR_INDEXSOURCE_CREATE_MISSING_NAME_0));
372        }
373        // already used? Don't test this at xml-configuration time (no manager)
374        if (OpenCms.getRunLevel() > OpenCms.RUNLEVEL_2_INITIALIZING) {
375            CmsSearchManager mngr = OpenCms.getSearchManager();
376            // don't test this if the indexsource is not new (widget invokes setName even if it was not changed)
377            if (mngr.getIndexSource(name) != this) {
378                if (mngr.getSearchIndexSources().keySet().contains(name)) {
379                    throw new CmsIllegalArgumentException(
380                        Messages.get().container(Messages.ERR_INDEXSOURCE_CREATE_INVALID_NAME_1, name));
381                }
382            }
383        }
384        m_name = name;
385    }
386
387    /**
388     * Sets the map of optional key/value parameters.<p>
389     *
390     * @param params the map of optional key/value parameters
391     */
392    public void setParams(Map<String, String> params) {
393
394        m_params = params;
395    }
396
397    /**
398     * Sets the list of Cms resources to be indexed.<p>
399     *
400     * @param resources the list of Cms resources (Strings) to be indexed
401     */
402    public void setResourcesNames(List<String> resources) {
403
404        m_resourcesNames = resources;
405    }
406}