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.configuration; 029 030import org.opencms.i18n.CmsLocaleComparator; 031import org.opencms.main.CmsLog; 032import org.opencms.main.OpenCms; 033import org.opencms.search.CmsSearchAnalyzer; 034import org.opencms.search.CmsSearchDocumentType; 035import org.opencms.search.CmsSearchIndex; 036import org.opencms.search.CmsSearchIndexSource; 037import org.opencms.search.CmsSearchManager; 038import org.opencms.search.fields.CmsLuceneField; 039import org.opencms.search.fields.CmsLuceneFieldConfiguration; 040import org.opencms.search.fields.CmsSearchField; 041import org.opencms.search.fields.CmsSearchFieldConfiguration; 042import org.opencms.search.fields.CmsSearchFieldMapping; 043import org.opencms.search.fields.CmsSearchFieldMappingType; 044import org.opencms.search.fields.I_CmsSearchFieldMapping; 045import org.opencms.search.solr.CmsSolrConfiguration; 046import org.opencms.util.CmsStringUtil; 047 048import java.util.ArrayList; 049import java.util.Collections; 050import java.util.Iterator; 051import java.util.Locale; 052import java.util.Map.Entry; 053 054import org.apache.commons.digester.Digester; 055 056import org.dom4j.Element; 057 058/** 059 * Lucene search configuration class.<p> 060 * 061 * @since 6.0.0 062 */ 063public class CmsSearchConfiguration extends A_CmsXmlConfiguration { 064 065 /** The "analyzer" attribute. */ 066 public static final String A_ANALYZER = "analyzer"; 067 068 /** The "boost" attribute. */ 069 public static final String A_BOOST = "boost"; 070 071 /** The "displayName" attribute. */ 072 public static final String A_DISPLAY = "display"; 073 074 /** The "excerpt" attribute. */ 075 public static final String A_EXCERPT = "excerpt"; 076 077 /** The "index" attribute. */ 078 public static final String A_INDEX = "index"; 079 080 /** The Solr server URL attribute, set if embedded = false. */ 081 public static final String A_SERVER_URL = "serverUrl"; 082 083 /** The "store" attribute. */ 084 public static final String A_STORE = "store"; 085 086 /** The name of the DTD for this configuration. */ 087 public static final String CONFIGURATION_DTD_NAME = "opencms-search.dtd"; 088 089 /** The name of the default XML file for this configuration. */ 090 public static final String DEFAULT_XML_FILE_NAME = "opencms-search.xml"; 091 092 /** Node name constant. */ 093 public static final String N_ANALYZER = "analyzer"; 094 095 /** Node name constant. */ 096 public static final String N_ANALYZERS = "analyzers"; 097 098 /** Node name constant. */ 099 public static final String N_CLASS = "class"; 100 101 /** Node name constant. */ 102 public static final String N_COMMIT_MS = "commitWithinMs"; 103 104 /** Node name constant. */ 105 public static final String N_CONFIG_FILE = "configfile"; 106 107 /** Node name constant. */ 108 public static final String N_CONFIGURATION = "configuration"; 109 110 /** Node name constant. */ 111 public static final String N_DESCRIPTION = "description"; 112 113 /** Node name constant. */ 114 public static final String N_DIRECTORY = "directory"; 115 116 /** Node name constant. */ 117 public static final String N_DOCUMENTTYPE = "documenttype"; 118 119 /** Node name constant. */ 120 public static final String N_DOCUMENTTYPES = "documenttypes"; 121 122 /** Node name constant. */ 123 public static final String N_DOCUMENTTYPES_INDEXED = "documenttypes-indexed"; 124 125 /** Node name constant. */ 126 public static final String N_EXCERPT = "excerpt"; 127 128 /** Node name constant. */ 129 public static final String N_EXTRACTION_CACHE_MAX_AGE = "extractionCacheMaxAge"; 130 131 /** Node name constant. */ 132 public static final String N_FIELD = "field"; 133 134 /** Node name constant. */ 135 public static final String N_FIELDCONFIGURATION = "fieldconfiguration"; 136 137 /** Node name constant. */ 138 public static final String N_FIELDCONFIGURATIONS = "fieldconfigurations"; 139 140 /** Node name constant. */ 141 public static final String N_FIELDS = "fields"; 142 143 /** Node name constant. */ 144 public static final String N_FORCEUNLOCK = "forceunlock"; 145 146 /** Node name constant. */ 147 public static final String N_HIGHLIGHTER = "highlighter"; 148 149 /** Node name constant. */ 150 public static final String N_HOME = "home"; 151 152 /** Node name constant. */ 153 public static final String N_INDEX = "index"; 154 155 /** Node name constant. */ 156 public static final String N_INDEXER = "indexer"; 157 158 /** Node name constant. */ 159 public static final String N_INDEXES = "indexes"; 160 161 /** Node name constant. */ 162 public static final String N_INDEXSOURCE = "indexsource"; 163 164 /** Node name constant. */ 165 public static final String N_INDEXSOURCES = "indexsources"; 166 167 /** Node name constant. */ 168 169 /** Node name constant. */ 170 public static final String N_LOCALE = "locale"; 171 172 /** Node name constant. */ 173 public static final String N_MAPPING = "mapping"; 174 175 /** Node name constant. */ 176 public static final String N_MAX_MODIFICATIONS_BEFORE_COMMIT = "maxModificationsBeforeCommit"; 177 178 /** Node name constant. */ 179 public static final String N_MIMETYPE = "mimetype"; 180 181 /** Node name constant. */ 182 public static final String N_MIMETYPES = "mimetypes"; 183 184 /** Node name constant. */ 185 public static final String N_OFFLINE_UPDATE_FREQUENCY = "offlineUpdateFrequency"; 186 187 /** Node name constant. */ 188 public static final String N_MAX_INDEX_WAIT_TIME = "maxIndexWaitTime"; 189 190 /** Node name constant. */ 191 public static final String N_PROJECT = "project"; 192 193 /** Node name constant. */ 194 public static final String N_REBUILD = "rebuild"; 195 196 /** Node name constant. */ 197 public static final String N_RESOURCES = "resources"; 198 199 /** Node name constant. */ 200 public static final String N_RESOURCETYPE = "resourcetype"; 201 202 /** Node name constant. */ 203 public static final String N_RESOURCETYPES = "resourcetypes"; 204 205 /** Node name constant. */ 206 public static final String N_SEARCH = "search"; 207 208 /** Node name constant. */ 209 public static final String N_SOLR = "solr"; 210 211 /** Node name constant. */ 212 public static final String N_SOURCE = "source"; 213 214 /** Node name constant. */ 215 public static final String N_SOURCES = "sources"; 216 217 /** Node name constant. */ 218 public static final String N_STEMMER = "stemmer"; 219 220 /** Node name constant. */ 221 public static final String N_TIMEOUT = "timeout"; 222 223 /** Node name constant. */ 224 private static final String XPATH_SEARCH = "*/" + N_SEARCH; 225 226 /** The configured search manager. */ 227 private CmsSearchManager m_searchManager; 228 229 /** 230 * @see org.opencms.configuration.I_CmsXmlConfiguration#addXmlDigesterRules(org.apache.commons.digester.Digester) 231 */ 232 public void addXmlDigesterRules(Digester digester) { 233 234 String xPath = null; 235 236 // add finish rule 237 digester.addCallMethod(XPATH_SEARCH, "initializeFinished"); 238 239 // creation of the search manager 240 digester.addObjectCreate(XPATH_SEARCH, A_CLASS, CmsSearchManager.class); 241 242 // search manager finished 243 digester.addSetNext(XPATH_SEARCH, "setSearchManager"); 244 245 // directory rule 246 digester.addCallMethod(XPATH_SEARCH + "/" + N_DIRECTORY, "setDirectory", 0); 247 248 // timeout rule 249 digester.addCallMethod(XPATH_SEARCH + "/" + N_TIMEOUT, "setTimeout", 0); 250 251 // offline update rule 252 digester.addCallMethod(XPATH_SEARCH + "/" + N_OFFLINE_UPDATE_FREQUENCY, "setOfflineUpdateFrequency", 0); 253 254 // offline update rule 255 digester.addCallMethod(XPATH_SEARCH + "/" + N_MAX_INDEX_WAIT_TIME, "setMaxIndexWaitTime", 0); 256 257 // forceunlock rule 258 digester.addCallMethod(XPATH_SEARCH + "/" + N_FORCEUNLOCK, "setForceunlock", 0); 259 260 // rule for the max. char. lenght of the search result excerpt 261 digester.addCallMethod(XPATH_SEARCH + "/" + N_EXCERPT, "setMaxExcerptLength", 0); 262 263 // rule for the max. age of entries in the extraction cache 264 digester.addCallMethod(XPATH_SEARCH + "/" + N_EXTRACTION_CACHE_MAX_AGE, "setExtractionCacheMaxAge", 0); 265 266 // rule for max. number of modifications before commit 267 digester.addCallMethod( 268 XPATH_SEARCH + "/" + N_MAX_MODIFICATIONS_BEFORE_COMMIT, 269 "setMaxModificationsBeforeCommit", 270 0); 271 272 // rule for the highlighter to highlight the search terms in the excerpt of the search result 273 digester.addCallMethod(XPATH_SEARCH + "/" + N_HIGHLIGHTER, "setHighlighter", 0); 274 275 xPath = XPATH_SEARCH + "/" + N_SOLR; 276 digester.addObjectCreate(xPath, CmsSolrConfiguration.class); 277 digester.addCallMethod(xPath, "setEnabled", 1); 278 digester.addCallParam(xPath, 0, A_ENABLED); 279 digester.addCallMethod(xPath, "setServerUrl", 1); 280 digester.addCallParam(xPath, 0, A_SERVER_URL); 281 digester.addCallMethod(xPath + "/" + N_HOME, "setHomeFolderPath", 0); 282 digester.addCallMethod(xPath + "/" + N_CONFIG_FILE, "setSolrFileName", 0); 283 digester.addCallMethod(xPath + "/" + N_COMMIT_MS, "setSolrCommitMs", 0); 284 digester.addSetNext(xPath, "setSolrServerConfiguration"); 285 286 // document type rule 287 xPath = XPATH_SEARCH + "/" + N_DOCUMENTTYPES + "/" + N_DOCUMENTTYPE; 288 digester.addObjectCreate(xPath, CmsSearchDocumentType.class); 289 digester.addCallMethod(xPath + "/" + N_NAME, "setName", 0); 290 digester.addCallMethod(xPath + "/" + N_CLASS, "setClassName", 0); 291 digester.addCallMethod(xPath + "/" + N_MIMETYPES + "/" + N_MIMETYPE, "addMimeType", 0); 292 digester.addCallMethod(xPath + "/" + N_RESOURCETYPES + "/" + N_RESOURCETYPE, "addResourceType", 0); 293 digester.addSetNext(xPath, "addDocumentTypeConfig"); 294 295 // analyzer rule 296 xPath = XPATH_SEARCH + "/" + N_ANALYZERS + "/" + N_ANALYZER; 297 digester.addObjectCreate(xPath, CmsSearchAnalyzer.class); 298 digester.addCallMethod(xPath + "/" + N_CLASS, "setClassName", 0); 299 digester.addCallMethod(xPath + "/" + N_STEMMER, "setStemmerAlgorithm", 0); 300 digester.addCallMethod(xPath + "/" + N_LOCALE, "setLocaleString", 0); 301 digester.addSetNext(xPath, "addAnalyzer"); 302 303 // search index rule 304 xPath = XPATH_SEARCH + "/" + N_INDEXES + "/" + N_INDEX; 305 digester.addObjectCreate(xPath, A_CLASS, CmsSearchIndex.class); 306 digester.addCallMethod(xPath + "/" + N_NAME, "setName", 0); 307 digester.addCallMethod(xPath + "/" + N_REBUILD, "setRebuildMode", 0); 308 digester.addCallMethod(xPath + "/" + N_PROJECT, "setProject", 0); 309 digester.addCallMethod(xPath + "/" + N_LOCALE, "setLocaleString", 0); 310 digester.addCallMethod(xPath + "/" + N_CONFIGURATION, "setFieldConfigurationName", 0); 311 digester.addCallMethod(xPath + "/" + N_SOURCES + "/" + N_SOURCE, "addSourceName", 0); 312 digester.addSetNext(xPath, "addSearchIndex"); 313 314 // search index source rule 315 xPath = XPATH_SEARCH + "/" + N_INDEXSOURCES + "/" + N_INDEXSOURCE; 316 digester.addObjectCreate(xPath, CmsSearchIndexSource.class); 317 digester.addCallMethod(xPath + "/" + N_NAME, "setName", 0); 318 digester.addCallMethod(xPath + "/" + N_INDEXER, "setIndexerClassName", 1); 319 digester.addCallParam(xPath + "/" + N_INDEXER, 0, N_CLASS); 320 digester.addCallMethod(xPath + "/" + N_RESOURCES + "/" + N_RESOURCE, "addResourceName", 0); 321 digester.addCallMethod(xPath + "/" + N_DOCUMENTTYPES_INDEXED + "/" + N_NAME, "addDocumentType", 0); 322 digester.addSetNext(xPath, "addSearchIndexSource"); 323 324 // field configuration rules 325 xPath = XPATH_SEARCH + "/" + N_FIELDCONFIGURATIONS + "/" + N_FIELDCONFIGURATION; 326 digester.addObjectCreate(xPath, A_CLASS, CmsLuceneFieldConfiguration.class); 327 digester.addCallMethod(xPath + "/" + N_NAME, "setName", 0); 328 digester.addCallMethod(xPath + "/" + N_DESCRIPTION, "setDescription", 0); 329 digester.addSetNext(xPath, "addFieldConfiguration"); 330 331 xPath = xPath + "/" + N_FIELDS + "/" + N_FIELD; 332 digester.addObjectCreate(xPath, CmsLuceneField.class); 333 digester.addCallMethod(xPath, "setName", 1); 334 digester.addCallParam(xPath, 0, I_CmsXmlConfiguration.A_NAME); 335 digester.addCallMethod(xPath, "setDisplayNameForConfiguration", 1); 336 digester.addCallParam(xPath, 0, A_DISPLAY); 337 digester.addCallMethod(xPath, "setStored", 1); 338 digester.addCallParam(xPath, 0, A_STORE); 339 digester.addCallMethod(xPath, "setIndexed", 1); 340 digester.addCallParam(xPath, 0, A_INDEX); 341 digester.addCallMethod(xPath, "setInExcerpt", 1); 342 digester.addCallParam(xPath, 0, A_EXCERPT); 343 digester.addCallMethod(xPath, "setAnalyzer", 1); 344 digester.addCallParam(xPath, 0, A_ANALYZER); 345 digester.addCallMethod(xPath, "setBoost", 1); 346 digester.addCallParam(xPath, 0, A_BOOST); 347 digester.addCallMethod(xPath, "setDefaultValue", 1); 348 digester.addCallParam(xPath, 0, A_DEFAULT); 349 digester.addCallMethod(xPath, "setType", 1); 350 digester.addCallParam(xPath, 0, A_TYPE); 351 digester.addSetNext(xPath, "addField"); 352 353 xPath = xPath + "/" + N_MAPPING; 354 digester.addObjectCreate(xPath, A_CLASS, CmsSearchFieldMapping.class); 355 digester.addCallMethod(xPath, "setDefaultValue", 1); 356 digester.addCallParam(xPath, 0, A_DEFAULT); 357 digester.addCallMethod(xPath, "setType", 1); 358 digester.addCallParam(xPath, 0, A_TYPE); 359 digester.addCallMethod(xPath, "setParam", 0); 360 digester.addSetNext(xPath, "addMapping"); 361 362 // generic <param> parameter rules 363 digester.addCallMethod( 364 "*/" + I_CmsXmlConfiguration.N_PARAM, 365 I_CmsConfigurationParameterHandler.ADD_PARAMETER_METHOD, 366 2); 367 digester.addCallParam("*/" + I_CmsXmlConfiguration.N_PARAM, 0, I_CmsXmlConfiguration.A_NAME); 368 digester.addCallParam("*/" + I_CmsXmlConfiguration.N_PARAM, 1); 369 } 370 371 /** 372 * @see org.opencms.configuration.I_CmsXmlConfiguration#generateXml(org.dom4j.Element) 373 */ 374 public Element generateXml(Element parent) { 375 376 // add <search> node 377 Element searchElement = parent.addElement(N_SEARCH); 378 if (OpenCms.getRunLevel() >= OpenCms.RUNLEVEL_3_SHELL_ACCESS) { 379 // initialized OpenCms instance is available, use latest values 380 m_searchManager = OpenCms.getSearchManager(); 381 } 382 383 // add class attribute (if required) 384 if (!m_searchManager.getClass().equals(CmsSearchManager.class)) { 385 searchElement.addAttribute(A_CLASS, m_searchManager.getClass().getName()); 386 } 387 388 // add the Solr node 389 if (m_searchManager.getSolrServerConfiguration() != null) { 390 Element solr = searchElement.addElement(N_SOLR); 391 CmsSolrConfiguration conf = m_searchManager.getSolrServerConfiguration(); 392 solr.addAttribute(A_ENABLED, new Boolean(conf.isEnabled()).toString()); 393 if (conf.getServerUrl() != null) { 394 solr.addAttribute(A_SERVER_URL, conf.getServerUrl().toString()); 395 } 396 if (conf.getHomeFolderPath() != null) { 397 solr.addElement(N_HOME).addText(conf.getHomeFolderPath()); 398 } 399 if (conf.getSolrFileName() != null) { 400 solr.addElement(N_CONFIG_FILE).addText(conf.getSolrFileName()); 401 } 402 solr.addElement(N_COMMIT_MS).addText(String.valueOf(conf.getSolrCommitMs())); 403 } 404 405 // add <directory> element 406 searchElement.addElement(N_DIRECTORY).addText(m_searchManager.getDirectory()); 407 // add <timeout> element 408 searchElement.addElement(N_TIMEOUT).addText(String.valueOf(m_searchManager.getTimeout())); 409 //add <offlineUpdateFrequency> element 410 searchElement.addElement(N_OFFLINE_UPDATE_FREQUENCY).addText( 411 String.valueOf(m_searchManager.getOfflineUpdateFrequency())); 412 //add <maxIndexWaitTime> element 413 searchElement.addElement(N_MAX_INDEX_WAIT_TIME).addText(String.valueOf(m_searchManager.getMaxIndexWaitTime())); 414 // add <forceunlock> element 415 if (m_searchManager.getForceunlock() != null) { 416 searchElement.addElement(N_FORCEUNLOCK).addText(m_searchManager.getForceunlock().toString()); 417 } 418 // add <exerpt> element 419 searchElement.addElement(N_EXCERPT).addText(String.valueOf(m_searchManager.getMaxExcerptLength())); 420 // add <extractionCacheMaxAge> element 421 searchElement.addElement(N_EXTRACTION_CACHE_MAX_AGE).addText( 422 String.valueOf(m_searchManager.getExtractionCacheMaxAge())); 423 // add <maxModificationsBeforeCommit> element 424 searchElement.addElement(N_MAX_MODIFICATIONS_BEFORE_COMMIT).addText( 425 String.valueOf(m_searchManager.getMaxModificationsBeforeCommit())); 426 // add <highlighter> element 427 searchElement.addElement(N_HIGHLIGHTER).addText(m_searchManager.getHighlighter().getClass().getName()); 428 429 // <documenttypes> 430 Element documenttypesElement = searchElement.addElement(N_DOCUMENTTYPES); 431 for (CmsSearchDocumentType currSearchDocType : m_searchManager.getDocumentTypeConfigs()) { 432 // add the next <documenttype> element 433 Element documenttypeElement = documenttypesElement.addElement(N_DOCUMENTTYPE); 434 // add <name> element 435 documenttypeElement.addElement(N_NAME).addText(currSearchDocType.getName()); 436 // add <class> element 437 documenttypeElement.addElement(N_CLASS).addText(currSearchDocType.getClassName()); 438 // add <mimetypes> element 439 Element mimetypesElement = documenttypeElement.addElement(N_MIMETYPES); 440 // get the list of mimetypes to trigger the document factory class 441 Iterator<String> mimeTypesIterator = currSearchDocType.getMimeTypes().iterator(); 442 while (mimeTypesIterator.hasNext()) { 443 // add <mimetype> element(s) 444 mimetypesElement.addElement(N_MIMETYPE).addText(mimeTypesIterator.next()); 445 } 446 // add <resourcetypes> element 447 Element restypesElement = documenttypeElement.addElement(N_RESOURCETYPES); 448 // get the list of Cms resource types to trigger the document factory 449 Iterator<String> resTypesIterator = currSearchDocType.getResourceTypes().iterator(); 450 while (resTypesIterator.hasNext()) { 451 // add <resourcetype> element(s) 452 restypesElement.addElement(N_RESOURCETYPE).addText(resTypesIterator.next()); 453 } 454 } 455 // </documenttypes> 456 457 // <analyzers> 458 Element analyzersElement = searchElement.addElement(N_ANALYZERS); 459 ArrayList<Locale> analyzerLocaleList = new ArrayList<Locale>(m_searchManager.getAnalyzers().keySet()); 460 // sort Analyzers in ascending order 461 Collections.sort(analyzerLocaleList, CmsLocaleComparator.getComparator()); 462 Iterator<Locale> analyzersLocaleInterator = analyzerLocaleList.iterator(); 463 while (analyzersLocaleInterator.hasNext()) { 464 CmsSearchAnalyzer searchAnalyzer = m_searchManager.getCmsSearchAnalyzer(analyzersLocaleInterator.next()); 465 // add the next <analyzer> element 466 Element analyzerElement = analyzersElement.addElement(N_ANALYZER); 467 // add <class> element 468 analyzerElement.addElement(N_CLASS).addText(searchAnalyzer.getClassName()); 469 // add <locale> element 470 analyzerElement.addElement(N_LOCALE).addText(searchAnalyzer.getLocale().toString()); 471 } 472 // </analyzers> 473 474 // <indexes> 475 Element indexesElement = searchElement.addElement(N_INDEXES); 476 for (CmsSearchIndex searchIndex : m_searchManager.getSearchIndexesAll()) { 477 // add the next <index> element 478 Element indexElement = indexesElement.addElement(N_INDEX); 479 // add class attribute (if required) 480 if (!searchIndex.getClass().equals(CmsSearchIndex.class)) { 481 indexElement.addAttribute(A_CLASS, searchIndex.getClass().getName()); 482 } 483 // add <name> element 484 indexElement.addElement(N_NAME).addText(searchIndex.getName()); 485 // add <rebuild> element 486 indexElement.addElement(N_REBUILD).addText(searchIndex.getRebuildMode()); 487 // add <project> element 488 indexElement.addElement(N_PROJECT).addText(searchIndex.getProject()); 489 // add <locale> element 490 indexElement.addElement(N_LOCALE).addText(searchIndex.getLocale().toString()); 491 // add <configuration> element 492 String fieldConfigurationName = searchIndex.getFieldConfigurationName(); 493 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(fieldConfigurationName)) { 494 indexElement.addElement(N_CONFIGURATION).addText(fieldConfigurationName); 495 } 496 // add <sources> element 497 Element sourcesElement = indexElement.addElement(N_SOURCES); 498 // iterate above sourcenames 499 Iterator<String> sourcesIterator = searchIndex.getSourceNames().iterator(); 500 while (sourcesIterator.hasNext()) { 501 // add <source> element 502 sourcesElement.addElement(N_SOURCE).addText(sourcesIterator.next()); 503 } 504 // iterate additional params 505 CmsParameterConfiguration indexConfiguration = searchIndex.getConfiguration(); 506 if (indexConfiguration != null) { 507 indexConfiguration.appendToXml(indexElement); 508 } 509 } 510 // </indexes> 511 512 // <indexsources> 513 Element indexsourcesElement = searchElement.addElement(N_INDEXSOURCES); 514 for (CmsSearchIndexSource searchIndexSource : m_searchManager.getSearchIndexSources().values()) { 515 // add <indexsource> element(s) 516 Element indexsourceElement = indexsourcesElement.addElement(N_INDEXSOURCE); 517 // add <name> element 518 indexsourceElement.addElement(N_NAME).addText(searchIndexSource.getName()); 519 // add <indexer class=""> element 520 Element indexerElement = indexsourceElement.addElement(N_INDEXER).addAttribute( 521 N_CLASS, 522 searchIndexSource.getIndexerClassName()); 523 for (Entry<String, String> entry : searchIndexSource.getParams().entrySet()) { 524 // add <param name=""> element(s) 525 indexerElement.addElement(I_CmsXmlConfiguration.N_PARAM).addAttribute( 526 I_CmsXmlConfiguration.A_NAME, 527 entry.getKey()).addText(entry.getValue()); 528 } 529 // add <resources> element 530 Element resourcesElement = indexsourceElement.addElement(N_RESOURCES); 531 Iterator<String> resourceIterator = searchIndexSource.getResourcesNames().iterator(); 532 while (resourceIterator.hasNext()) { 533 // add <resource> element(s) 534 resourcesElement.addElement(N_RESOURCE).addText(resourceIterator.next()); 535 } 536 // add <documenttypes-indexed> element 537 Element doctypes_indexedElement = indexsourceElement.addElement(N_DOCUMENTTYPES_INDEXED); 538 Iterator<String> doctypesIterator = searchIndexSource.getDocumentTypes().iterator(); 539 while (doctypesIterator.hasNext()) { 540 // add <name> element(s) 541 doctypes_indexedElement.addElement(N_NAME).addText(doctypesIterator.next()); 542 } 543 } 544 // </indexsources> 545 546 // <fieldconfigurations> 547 Element fieldConfigurationsElement = searchElement.addElement(N_FIELDCONFIGURATIONS); 548 for (CmsSearchFieldConfiguration fieldConfiguration : m_searchManager.getFieldConfigurations()) { 549 Element fieldConfigurationElement = fieldConfigurationsElement.addElement(N_FIELDCONFIGURATION); 550 // add class attribute (if required) 551 if (!fieldConfiguration.getClass().equals(CmsLuceneFieldConfiguration.class)) { 552 fieldConfigurationElement.addAttribute(A_CLASS, fieldConfiguration.getClass().getName()); 553 } 554 fieldConfigurationElement.addElement(N_NAME).setText(fieldConfiguration.getName()); 555 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(fieldConfiguration.getDescription())) { 556 fieldConfigurationElement.addElement(N_DESCRIPTION).setText(fieldConfiguration.getDescription()); 557 } 558 // search fields 559 Element fieldsElement = fieldConfigurationElement.addElement(N_FIELDS); 560 for (CmsSearchField sfield : fieldConfiguration.getFields()) { 561 if (sfield instanceof CmsLuceneField) { 562 CmsLuceneField field = (CmsLuceneField)sfield; 563 Element fieldElement = fieldsElement.addElement(N_FIELD); 564 fieldElement.addAttribute(A_NAME, field.getName()); 565 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(field.getDisplayNameForConfiguration())) { 566 fieldElement.addAttribute(A_DISPLAY, field.getDisplayNameForConfiguration()); 567 } 568 if (field.isCompressed()) { 569 fieldElement.addAttribute(A_STORE, CmsLuceneField.STR_COMPRESS); 570 } else { 571 fieldElement.addAttribute(A_STORE, String.valueOf(field.isStored())); 572 } 573 String index; 574 if (field.isIndexed()) { 575 if (field.isTokenizedAndIndexed()) { 576 // index and tokenized 577 index = CmsStringUtil.TRUE; 578 } else { 579 // indexed but not tokenized 580 index = CmsLuceneField.STR_UN_TOKENIZED; 581 } 582 } else { 583 // not indexed at all 584 index = CmsStringUtil.FALSE; 585 } 586 fieldElement.addAttribute(A_INDEX, index); 587 if (field.getBoost() != CmsSearchField.BOOST_DEFAULT) { 588 fieldElement.addAttribute(A_BOOST, String.valueOf(field.getBoost())); 589 } 590 if (field.isInExcerptAndStored()) { 591 fieldElement.addAttribute(A_EXCERPT, String.valueOf(true)); 592 } 593 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(field.getDefaultValue())) { 594 fieldElement.addAttribute(A_DEFAULT, field.getDefaultValue()); 595 } 596 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(field.getType())) { 597 fieldElement.addAttribute(A_TYPE, field.getType()); 598 } 599 if (field.getAnalyzer() != null) { 600 String className = field.getAnalyzer().getClass().getName(); 601 if (className.startsWith(CmsSearchManager.LUCENE_ANALYZER)) { 602 className = className.substring(CmsSearchManager.LUCENE_ANALYZER.length()); 603 } 604 fieldElement.addAttribute(A_ANALYZER, className); 605 } 606 // field mappings 607 for (I_CmsSearchFieldMapping mapping : field.getMappings()) { 608 Element mappingElement = fieldElement.addElement(N_MAPPING); 609 mappingElement.addAttribute(A_TYPE, mapping.getType().toString()); 610 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(mapping.getDefaultValue())) { 611 mappingElement.addAttribute(A_DEFAULT, mapping.getDefaultValue()); 612 } 613 // add class attribute (if required) 614 if (!mapping.getClass().equals(CmsSearchFieldMapping.class) 615 || (mapping.getType() == CmsSearchFieldMappingType.DYNAMIC)) { 616 mappingElement.addAttribute(A_CLASS, mapping.getClass().getName()); 617 } 618 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(mapping.getParam())) { 619 mappingElement.setText(mapping.getParam()); 620 } 621 } 622 } 623 } 624 } 625 // </fieldconfigurations> 626 627 return searchElement; 628 } 629 630 /** 631 * @see org.opencms.configuration.I_CmsXmlConfiguration#getDtdFilename() 632 */ 633 public String getDtdFilename() { 634 635 return CONFIGURATION_DTD_NAME; 636 } 637 638 /** 639 * Returns the generated search manager.<p> 640 * 641 * @return the generated search manager 642 */ 643 public CmsSearchManager getSearchManager() { 644 645 return m_searchManager; 646 } 647 648 /** 649 * Will be called when configuration of this object is finished.<p> 650 */ 651 public void initializeFinished() { 652 653 if (CmsLog.INIT.isInfoEnabled()) { 654 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_SEARCH_CONFIG_FINISHED_0)); 655 } 656 } 657 658 /** 659 * Sets the generated search manager.<p> 660 * 661 * @param manager the search manager to set 662 */ 663 public void setSearchManager(CmsSearchManager manager) { 664 665 m_searchManager = manager; 666 if (CmsLog.INIT.isInfoEnabled()) { 667 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_SEARCH_MANAGER_FINISHED_0)); 668 } 669 } 670 671 /** 672 * @see org.opencms.configuration.A_CmsXmlConfiguration#initMembers() 673 */ 674 @Override 675 protected void initMembers() { 676 677 setXmlFileName(DEFAULT_XML_FILE_NAME); 678 if (CmsLog.INIT.isInfoEnabled()) { 679 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_SEARCH_CONFIG_INIT_0)); 680 } 681 } 682}