001/* 002 * File : $Source$ 003 * Date : $Date$ 004 * Version: $Revision$ 005 * 006 * This library is part of OpenCms - 007 * the Open Source Content Management System 008 * 009 * Copyright (C) 2002 - 2009 Alkacon Software (http://www.alkacon.com) 010 * 011 * This library is free software; you can redistribute it and/or 012 * modify it under the terms of the GNU Lesser General Public 013 * License as published by the Free Software Foundation; either 014 * version 2.1 of the License, or (at your option) any later version. 015 * 016 * This library is distributed in the hope that it will be useful, 017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 019 * Lesser General Public License for more details. 020 * 021 * For further information about Alkacon Software, please see the 022 * company website: http://www.alkacon.com 023 * 024 * For further information about OpenCms, please see the 025 * project website: http://www.opencms.org 026 * 027 * You should have received a copy of the GNU Lesser General Public 028 * License along with this library; if not, write to the Free Software 029 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 030 */ 031 032package org.opencms.search.solr; 033 034import org.opencms.acacia.shared.I_CmsSerialDateValue; 035import org.opencms.ade.containerpage.CmsDetailOnlyContainerUtil; 036import org.opencms.file.CmsFile; 037import org.opencms.file.CmsObject; 038import org.opencms.file.CmsPropertyDefinition; 039import org.opencms.file.CmsResource; 040import org.opencms.file.types.CmsResourceTypeXmlContent; 041import org.opencms.file.types.I_CmsResourceType; 042import org.opencms.i18n.CmsLocaleManager; 043import org.opencms.main.CmsException; 044import org.opencms.main.CmsLog; 045import org.opencms.main.OpenCms; 046import org.opencms.search.CmsIndexException; 047import org.opencms.search.CmsSearchUtil; 048import org.opencms.search.I_CmsSearchIndex; 049import org.opencms.search.documents.A_CmsVfsDocument; 050import org.opencms.search.documents.CmsIndexNoContentException; 051import org.opencms.search.documents.Messages; 052import org.opencms.search.extractors.CmsExtractionResult; 053import org.opencms.search.extractors.I_CmsExtractionResult; 054import org.opencms.search.fields.CmsSearchField; 055import org.opencms.search.fields.CmsSearchFieldConfiguration; 056import org.opencms.search.galleries.CmsGalleryNameMacroResolver; 057import org.opencms.util.CmsStringUtil; 058import org.opencms.widgets.serialdate.CmsSerialDateBeanFactory; 059import org.opencms.widgets.serialdate.CmsSerialDateValue; 060import org.opencms.widgets.serialdate.I_CmsSerialDateBean; 061import org.opencms.xml.A_CmsXmlDocument; 062import org.opencms.xml.CmsXmlContentDefinition; 063import org.opencms.xml.CmsXmlUtils; 064import org.opencms.xml.content.CmsXmlContent; 065import org.opencms.xml.content.CmsXmlContentFactory; 066import org.opencms.xml.content.I_CmsXmlContentHandler; 067import org.opencms.xml.types.CmsXmlDateTimeValue; 068import org.opencms.xml.types.CmsXmlHtmlValue; 069import org.opencms.xml.types.CmsXmlNestedContentDefinition; 070import org.opencms.xml.types.CmsXmlSerialDateValue; 071import org.opencms.xml.types.I_CmsXmlContentValue; 072import org.opencms.xml.types.I_CmsXmlSchemaType; 073 074import java.util.ArrayList; 075import java.util.Collections; 076import java.util.HashMap; 077import java.util.Iterator; 078import java.util.LinkedHashMap; 079import java.util.List; 080import java.util.Locale; 081import java.util.Map; 082import java.util.Set; 083 084import org.apache.commons.logging.Log; 085 086import com.google.common.collect.Sets; 087 088/** 089 * Special document text extraction factory for Solr index.<p> 090 * 091 * @since 8.5.0 092 */ 093public class CmsSolrDocumentXmlContent extends A_CmsVfsDocument { 094 095 /** 096 * The gallery name is determined by resolving the macros in a string which can either come from a field mapped 097 * to the gallery name, or the title, or from default values for those fields. This class is used to select the 098 * value to use and performs the macro substitution. 099 */ 100 private static class GalleryNameChooser { 101 102 /** CMS context for this instance. */ 103 private CmsObject m_cms; 104 105 /** Current XML content. */ 106 private A_CmsXmlDocument m_content; 107 108 /** Default value of field mapped to gallery name. */ 109 private String m_defaultGalleryNameValue; 110 111 /** Default value of field mapped to title. */ 112 private String m_defaultTitleValue; 113 114 /** Current locale. */ 115 private Locale m_locale; 116 117 /** Content value mapped to Description property. */ 118 private String m_mappedDescriptionValue; 119 120 /** Content value mapped to gallery description. */ 121 private String m_mappedGalleryDescriptionValue; 122 123 /** Content value mapped to gallery name. */ 124 private String m_mappedGalleryNameValue; 125 126 /** Content value mapped to title. */ 127 private String m_mappedTitleValue; 128 129 /** 130 * Creates a new instance.<p> 131 * 132 * @param cms the CMS context 133 * @param content the XML content 134 * @param locale the locale in the XML content 135 */ 136 public GalleryNameChooser(CmsObject cms, A_CmsXmlDocument content, Locale locale) { 137 138 m_cms = cms; 139 m_content = content; 140 m_locale = locale; 141 } 142 143 /** 144 * Selects the description displayed in the gallery.<p> 145 * 146 * This method assumes that all the available values have been set via the setters of this class. 147 * 148 * @return the description 149 * 150 * @throws CmsException of something goes wrong 151 */ 152 public String getDescription() throws CmsException { 153 154 return getDescription(m_locale); 155 } 156 157 /** 158 * Selects the description displayed in the gallery.<p> 159 * 160 * This method assumes that all the available values have been set via the setters of this class. 161 * 162 * @param locale the locale to get the description in 163 * 164 * @return the description 165 * 166 * @throws CmsException of something goes wrong 167 */ 168 public String getDescription(Locale locale) throws CmsException { 169 170 String result = null; 171 for (String resultCandidateWithMacros : new String[] { 172 m_mappedGalleryDescriptionValue, 173 m_mappedDescriptionValue}) { 174 if (!CmsStringUtil.isEmptyOrWhitespaceOnly(resultCandidateWithMacros)) { 175 CmsGalleryNameMacroResolver resolver = new CmsGalleryNameMacroResolver(m_cms, m_content, locale); 176 result = resolver.resolveMacros(resultCandidateWithMacros); 177 return result; 178 } 179 } 180 result = m_cms.readPropertyObject( 181 m_content.getFile(), 182 CmsPropertyDefinition.PROPERTY_DESCRIPTION, 183 false).getValue(); 184 return result; 185 } 186 187 /** 188 * Selects the gallery name.<p> 189 * 190 * This method assumes that all the available values have been set via the setters of this class. 191 * 192 * @return the gallery name 193 * 194 * @throws CmsException of something goes wrong 195 */ 196 public String getGalleryName() throws CmsException { 197 198 return getGalleryName(m_locale); 199 } 200 201 /** 202 * Selects the gallery name.<p> 203 * 204 * This method assumes that all the available values have been set via the setters of this class. 205 * 206 * @param locale the locale to get the gallery name in 207 * 208 * @return the gallery name 209 * 210 * @throws CmsException of something goes wrong 211 */ 212 public String getGalleryName(Locale locale) throws CmsException { 213 214 String result = null; 215 for (String resultCandidateWithMacros : new String[] { 216 // Prioritize gallery name over title, and actual content values over defaults 217 m_mappedGalleryNameValue, 218 m_defaultGalleryNameValue, 219 m_mappedTitleValue, 220 m_defaultTitleValue}) { 221 if (!CmsStringUtil.isEmptyOrWhitespaceOnly(resultCandidateWithMacros)) { 222 CmsGalleryNameMacroResolver resolver = new CmsGalleryNameMacroResolver(m_cms, m_content, locale); 223 result = resolver.resolveMacros(resultCandidateWithMacros); 224 return result; 225 } 226 } 227 result = m_cms.readPropertyObject( 228 m_content.getFile(), 229 CmsPropertyDefinition.PROPERTY_TITLE, 230 false).getValue(); 231 return result; 232 } 233 234 /** 235 * Sets the defaultGalleryNameValue.<p> 236 * 237 * @param defaultGalleryNameValue the defaultGalleryNameValue to set 238 */ 239 public void setDefaultGalleryNameValue(String defaultGalleryNameValue) { 240 241 m_defaultGalleryNameValue = defaultGalleryNameValue; 242 } 243 244 /** 245 * Sets the defaultTitleValue.<p> 246 * 247 * @param defaultTitleValue the defaultTitleValue to set 248 */ 249 public void setDefaultTitleValue(String defaultTitleValue) { 250 251 m_defaultTitleValue = defaultTitleValue; 252 } 253 254 /** 255 * Sets the mapped description value.<p> 256 * 257 * @param mappedDescriptionValue the mappedDescriptionValue to set 258 */ 259 public void setMappedDescriptionValue(String mappedDescriptionValue) { 260 261 m_mappedDescriptionValue = mappedDescriptionValue; 262 } 263 264 /** 265 * Sets the name from a value mapped via 'galleryDescription'. 266 * 267 * @param mappedGalleryDescriptionValue the value that has been mapped 268 */ 269 public void setMappedGalleryDescriptionValue(String mappedGalleryDescriptionValue) { 270 271 m_mappedGalleryDescriptionValue = mappedGalleryDescriptionValue; 272 } 273 274 /** 275 * Sets the mappedGalleryNameValue.<p> 276 * 277 * @param mappedGalleryNameValue the mappedGalleryNameValue to set 278 */ 279 public void setMappedGalleryNameValue(String mappedGalleryNameValue) { 280 281 m_mappedGalleryNameValue = mappedGalleryNameValue; 282 } 283 284 /** 285 * Sets the mappedTitleValue.<p> 286 * 287 * @param mappedTitleValue the mappedTitleValue to set 288 */ 289 public void setMappedTitleValue(String mappedTitleValue) { 290 291 m_mappedTitleValue = mappedTitleValue; 292 } 293 } 294 295 /** Mapping name used to indicate that the value should be used for the gallery description. */ 296 public static final String MAPPING_GALLERY_DESCRIPTION = "galleryDescription"; 297 298 /** Mapping name used to indicate that the value should be used for the gallery name. */ 299 public static final String MAPPING_GALLERY_NAME = "galleryName"; 300 301 /** The solr document type name for xml-contents. */ 302 public static final String TYPE_XMLCONTENT_SOLR = "xmlcontent-solr"; 303 304 /** The log object for this class. */ 305 private static final Log LOG = CmsLog.getLog(CmsSolrDocumentXmlContent.class); 306 307 /** 308 * Public constructor.<p> 309 * 310 * @param name the name for the document type 311 */ 312 public CmsSolrDocumentXmlContent(String name) { 313 314 super(name); 315 } 316 317 /** 318 * Collects a list of all possible XPaths for a content definition.<p> 319 * 320 * @param cms the CMS context to use 321 * @param def the content definition 322 * @param path the path of the given content definition 323 * @param result the set used to collect the XPaths 324 */ 325 public static void collectSchemaXpathsForSimpleValues( 326 CmsObject cms, 327 CmsXmlContentDefinition def, 328 String path, 329 Set<String> result) { 330 331 List<I_CmsXmlSchemaType> nestedTypes = def.getTypeSequence(); 332 for (I_CmsXmlSchemaType nestedType : nestedTypes) { 333 String subPath = path + "/" + nestedType.getName(); 334 if (nestedType instanceof CmsXmlNestedContentDefinition) { 335 CmsXmlContentDefinition nestedDef = ((CmsXmlNestedContentDefinition)nestedType).getNestedContentDefinition(); 336 collectSchemaXpathsForSimpleValues(cms, nestedDef, subPath, result); 337 } else { 338 result.add(subPath); 339 } 340 } 341 } 342 343 /** 344 * Extracts the content of a single XML content resource.<p> 345 * 346 * @param cms the cms context 347 * @param resource the resource 348 * @param index the used index 349 * 350 * @return the extraction result 351 * 352 * @throws CmsException in case reading or unmarshalling the content fails 353 */ 354 public static CmsExtractionResult extractXmlContent(CmsObject cms, CmsResource resource, I_CmsSearchIndex index) 355 throws CmsException { 356 357 return extractXmlContent(cms, resource, index, null); 358 } 359 360 /** 361 * Extracts the content of a single XML content resource.<p> 362 * 363 * @param cms the cms context 364 * @param resource the resource 365 * @param index the used index 366 * @param forceLocale if set, only the content values for the given locale will be extracted 367 * 368 * @return the extraction result 369 * 370 * @throws CmsException in case reading or unmarshalling the content fails 371 */ 372 public static CmsExtractionResult extractXmlContent( 373 CmsObject cms, 374 CmsResource resource, 375 I_CmsSearchIndex index, 376 Locale forceLocale) 377 throws CmsException { 378 379 // un-marshal the content 380 CmsFile file = cms.readFile(resource); 381 if (file.getLength() <= 0) { 382 throw new CmsIndexNoContentException( 383 Messages.get().container(Messages.ERR_NO_CONTENT_1, resource.getRootPath())); 384 } 385 A_CmsXmlDocument xmlContent = CmsXmlContentFactory.unmarshal(cms, file); 386 387 // initialize some variables 388 Map<Locale, LinkedHashMap<String, String>> items = new HashMap<Locale, LinkedHashMap<String, String>>(); 389 Map<String, String> fieldMappings = new HashMap<String, String>(); 390 List<Locale> contentLocales = forceLocale != null 391 ? Collections.singletonList(forceLocale) 392 : xmlContent.getLocales(); 393 Locale resourceLocale = index.getLocaleForResource(cms, resource, contentLocales); 394 395 LinkedHashMap<String, String> localeItems = null; 396 GalleryNameChooser galleryNameChooser = null; 397 // loop over the locales of the content 398 for (Locale locale : contentLocales) { 399 galleryNameChooser = new GalleryNameChooser(cms, xmlContent, locale); 400 localeItems = new LinkedHashMap<String, String>(); 401 StringBuffer textContent = new StringBuffer(); 402 // store the locales of the content as space separated field 403 // loop over the available element paths of the current content locale 404 List<String> paths = xmlContent.getNames(locale); 405 for (String xpath : paths) { 406 407 // try to get the value extraction for the current element path 408 String extracted = null; 409 I_CmsXmlContentValue value = xmlContent.getValue(xpath, locale); 410 try { 411 //the new DatePointField.createField dose not support milliseconds 412 if (value instanceof CmsXmlDateTimeValue) { 413 extracted = CmsSearchUtil.getDateAsIso8601(((CmsXmlDateTimeValue)value).getDateTimeValue()); 414 } else { 415 extracted = value.getPlainText(cms); 416 if (CmsStringUtil.isEmptyOrWhitespaceOnly(extracted) 417 && value.isSimpleType() 418 && !(value instanceof CmsXmlHtmlValue)) { 419 // no text value for simple type, so take the string value as item 420 // prevent this for elements of type "OpenCmsHtml", since this causes problematic values 421 // being indexed, e.g., <iframe ...></iframe> 422 // TODO: Why is this special handling needed at all??? 423 extracted = value.getStringValue(cms); 424 } 425 } 426 } catch (Exception e) { 427 // it can happen that a exception is thrown while extracting a single value 428 LOG.warn(Messages.get().container(Messages.LOG_EXTRACT_VALUE_2, xpath, resource), e); 429 } 430 431 // put the extraction to the items and to the textual content 432 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(extracted)) { 433 localeItems.put(xpath, extracted); 434 } 435 if (value.getContentDefinition().getContentHandler().isSearchable(value) 436 && CmsStringUtil.isNotEmptyOrWhitespaceOnly(extracted)) { 437 // value is search-able and the extraction is not empty, so added to the textual content 438 textContent.append(extracted); 439 textContent.append('\n'); 440 } 441 442 List<String> mappings = xmlContent.getHandler().getMappings(value.getPath()); 443 if (mappings.size() > 0) { 444 // mappings are defined, lets check if we have mappings that interest us 445 for (String mapping : mappings) { 446 if (mapping.startsWith(I_CmsXmlContentHandler.MAPTO_PROPERTY)) { 447 // this is a property mapping 448 String propertyName = mapping.substring(mapping.lastIndexOf(':') + 1); 449 if (CmsPropertyDefinition.PROPERTY_TITLE.equals(propertyName) 450 || CmsPropertyDefinition.PROPERTY_DESCRIPTION.equals(propertyName)) { 451 452 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(extracted)) { 453 if (CmsPropertyDefinition.PROPERTY_TITLE.equals(propertyName)) { 454 galleryNameChooser.setMappedTitleValue(extracted); 455 } else { 456 // if field is not title, it must be description 457 galleryNameChooser.setMappedDescriptionValue(extracted); 458 } 459 } 460 } 461 } else if (mapping.equals(MAPPING_GALLERY_NAME)) { 462 galleryNameChooser.setMappedGalleryNameValue(value.getPlainText(cms)); 463 } else if (mapping.equals(MAPPING_GALLERY_DESCRIPTION)) { 464 galleryNameChooser.setMappedGalleryDescriptionValue(value.getPlainText(cms)); 465 } 466 } 467 } 468 if (value instanceof CmsXmlSerialDateValue) { 469 if ((null != extracted) && !extracted.isEmpty()) { 470 I_CmsSerialDateValue serialDateValue = new CmsSerialDateValue(extracted); 471 I_CmsSerialDateBean serialDateBean = CmsSerialDateBeanFactory.createSerialDateBean( 472 serialDateValue); 473 if (null != serialDateBean) { 474 StringBuffer values = new StringBuffer(); 475 StringBuffer endValues = new StringBuffer(); 476 StringBuffer currentTillValues = new StringBuffer(); 477 for (Long eventDate : serialDateBean.getDatesAsLong()) { 478 values.append("\n").append(eventDate.toString()); 479 long endDate = null != serialDateBean.getEventDuration() 480 ? eventDate.longValue() + serialDateBean.getEventDuration().longValue() 481 : eventDate.longValue(); 482 endValues.append("\n").append(Long.toString(endDate)); 483 // Special treatment for events that end at 00:00: 484 // To not show them at the day after they ended, one millisecond is removed from the end time 485 // for the "currenttill"-time 486 currentTillValues.append("\n").append( 487 serialDateValue.isCurrentTillEnd() 488 ? Long.valueOf( 489 serialDateValue.endsAtMidNight() && (endDate > eventDate.longValue()) 490 ? endDate - 1L 491 : endDate) 492 : eventDate); 493 } 494 fieldMappings.put(CmsSearchField.FIELD_SERIESDATES, values.substring(1)); 495 fieldMappings.put(CmsSearchField.FIELD_SERIESDATES_END, endValues.substring(1)); 496 fieldMappings.put( 497 CmsSearchField.FIELD_SERIESDATES_CURRENT_TILL, 498 currentTillValues.substring(1)); 499 fieldMappings.put( 500 CmsSearchField.FIELD_SERIESDATES_TYPE, 501 serialDateValue.getDateType().toString()); 502 } else { 503 LOG.warn( 504 "Serial date value \"" 505 + value.getStringValue(cms) 506 + "\" at element \"" 507 + value.getPath() 508 + "\" is invalid. No dates are indexed for resource \"" 509 + resource.getRootPath() 510 + "\"."); 511 } 512 } 513 } 514 } 515 516 Set<String> xpaths = Sets.newHashSet(); 517 collectSchemaXpathsForSimpleValues(cms, xmlContent.getContentDefinition(), "", xpaths); 518 for (String xpath : xpaths) { 519 // mappings always are stored with indexes, so we add them to the xpath 520 List<String> mappings = xmlContent.getHandler().getMappings(CmsXmlUtils.createXpath(xpath, 1)); 521 for (String mapping : mappings) { 522 523 if (mapping.equals(MAPPING_GALLERY_NAME) 524 || mapping.equals( 525 I_CmsXmlContentHandler.MAPTO_PROPERTY + CmsPropertyDefinition.PROPERTY_TITLE)) { 526 String defaultValue = xmlContent.getHandler().getDefault( 527 cms, 528 xmlContent.getFile(), 529 null, 530 xpath, 531 locale); 532 if (mapping.equals(MAPPING_GALLERY_NAME)) { 533 galleryNameChooser.setDefaultGalleryNameValue(defaultValue); 534 } else { 535 galleryNameChooser.setDefaultTitleValue(defaultValue); 536 } 537 } 538 } 539 } 540 541 final String galleryTitleFieldKey = CmsSearchFieldConfiguration.getLocaleExtendedName( 542 CmsSearchField.FIELD_TITLE_UNSTORED, 543 locale) + "_s"; 544 final String galleryNameValue = galleryNameChooser.getGalleryName(); 545 fieldMappings.put(galleryTitleFieldKey, galleryNameValue); 546 fieldMappings.put( 547 CmsSearchFieldConfiguration.getLocaleExtendedName(CmsSearchField.FIELD_DESCRIPTION, locale) + "_s", 548 galleryNameChooser.getDescription()); 549 550 // handle the textual content 551 if (textContent.length() > 0) { 552 // add the textual content with a localized key to the items 553 //String key = CmsSearchFieldConfiguration.getLocaleExtendedName(CmsSearchField.FIELD_CONTENT, locale); 554 //items.put(key, textContent.toString()); 555 // use the default locale of this resource as general text content for the extraction result 556 localeItems.put(I_CmsExtractionResult.ITEM_CONTENT, textContent.toString()); 557 } 558 items.put(locale, localeItems); 559 } 560 // if the content is locale independent, it should have only one content locale, but that should be indexed for all available locales. 561 // TODO: One could think of different indexing behavior, i.e., index only for getDefaultLocales(cms,resource) 562 // But using getAvailableLocales(cms,resource) does not work, because locale-available is set to "en" for all that content. 563 if ((xmlContent instanceof CmsXmlContent) && ((CmsXmlContent)xmlContent).isLocaleIndependent()) { 564 if (forceLocale != null) { 565 items.put(forceLocale, localeItems); 566 } else { 567 for (Locale l : OpenCms.getLocaleManager().getAvailableLocales()) { 568 items.put(l, localeItems); 569 if (null != galleryNameChooser) { 570 final String galleryTitleFieldKey = CmsSearchFieldConfiguration.getLocaleExtendedName( 571 CmsSearchField.FIELD_TITLE_UNSTORED, 572 l) + "_s"; 573 fieldMappings.put(galleryTitleFieldKey, galleryNameChooser.getGalleryName(l)); 574 fieldMappings.put( 575 CmsSearchFieldConfiguration.getLocaleExtendedName(CmsSearchField.FIELD_DESCRIPTION, l) 576 + "_s", 577 galleryNameChooser.getDescription(l)); 578 } 579 } 580 } 581 } 582 // add the locales that have been indexed for this document as item and return the extraction result 583 // fieldMappings.put(CmsSearchField.FIELD_RESOURCE_LOCALES, locales.toString().trim()); 584 return new CmsExtractionResult(resourceLocale, items, fieldMappings); 585 586 } 587 588 /** 589 * @see org.opencms.search.documents.CmsDocumentXmlContent#extractContent(org.opencms.file.CmsObject, org.opencms.file.CmsResource, org.opencms.search.I_CmsSearchIndex) 590 */ 591 @Override 592 public I_CmsExtractionResult extractContent(CmsObject cms, CmsResource resource, I_CmsSearchIndex index) 593 throws CmsException { 594 595 logContentExtraction(resource, index); 596 597 try { 598 I_CmsExtractionResult result = null; 599 List<I_CmsExtractionResult> ex = new ArrayList<I_CmsExtractionResult>(); 600 for (CmsResource detailContainers : CmsDetailOnlyContainerUtil.getDetailOnlyResources(cms, resource)) { 601 CmsSolrDocumentContainerPage containerpageExtractor = new CmsSolrDocumentContainerPage(""); 602 String localeTemp = detailContainers.getRootPath(); 603 localeTemp = CmsResource.getParentFolder(localeTemp); 604 localeTemp = CmsResource.getName(localeTemp); 605 localeTemp = localeTemp.substring(0, localeTemp.length() - 1); 606 Locale locale = CmsLocaleManager.getLocale(localeTemp); 607 if (CmsDetailOnlyContainerUtil.useSingleLocaleDetailContainers( 608 OpenCms.getSiteManager().getSiteRoot(resource.getRootPath())) 609 && locale.equals(CmsLocaleManager.getDefaultLocale())) { 610 // in case of single locale detail containers do not force the locale 611 locale = null; 612 } 613 I_CmsExtractionResult containersExtractionResult = containerpageExtractor.extractContent( 614 cms, 615 detailContainers, 616 index, 617 locale); 618 // only use the locales of the resource itself, not the ones of the detail containers page 619 containersExtractionResult.getContentItems().remove(CmsSearchField.FIELD_RESOURCE_LOCALES); 620 621 ex.add(containersExtractionResult); 622 } 623 result = extractXmlContent(cms, resource, index); 624 result = result.merge(ex); 625 return result; 626 627 } catch (Throwable t) { 628 throw new CmsIndexException(Messages.get().container(Messages.ERR_TEXT_EXTRACTION_1, resource), t); 629 } 630 } 631 632 /** 633 * @see org.opencms.search.documents.I_CmsDocumentFactory#getDocumentKeys(java.util.List, java.util.List) 634 */ 635 @Override 636 public List<String> getDocumentKeys(List<String> resourceTypes, List<String> mimeTypes) throws CmsException { 637 638 if (resourceTypes.contains("*")) { 639 // we need to find all configured XML content types 640 List<String> allTypes = new ArrayList<String>(); 641 for (Iterator<I_CmsResourceType> i = OpenCms.getResourceManager().getResourceTypes().iterator(); i.hasNext();) { 642 I_CmsResourceType resourceType = i.next(); 643 if ((resourceType instanceof CmsResourceTypeXmlContent) 644 // either we need a configured schema, or another class name (which must then contain an inline schema) 645 && (((CmsResourceTypeXmlContent)resourceType).getConfiguration().containsKey( 646 CmsResourceTypeXmlContent.CONFIGURATION_SCHEMA) 647 || !CmsResourceTypeXmlContent.class.equals(resourceType.getClass()))) { 648 // add the XML content resource type name 649 allTypes.add(resourceType.getTypeName()); 650 } 651 } 652 resourceTypes = allTypes; 653 } 654 655 return super.getDocumentKeys(resourceTypes, mimeTypes); 656 } 657 658 /** 659 * Solr index content is stored in multiple languages, so the result is NOT locale dependent.<p> 660 * 661 * @see org.opencms.search.documents.I_CmsDocumentFactory#isLocaleDependend() 662 */ 663 public boolean isLocaleDependend() { 664 665 return false; 666 } 667 668 /** 669 * @see org.opencms.search.documents.I_CmsDocumentFactory#isUsingCache() 670 */ 671 public boolean isUsingCache() { 672 673 return true; 674 } 675}