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