001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.search.galleries; 029 030import org.opencms.file.CmsObject; 031import org.opencms.file.CmsProperty; 032import org.opencms.file.CmsPropertyDefinition; 033import org.opencms.file.CmsResource; 034import org.opencms.file.types.CmsResourceTypeFunctionConfig; 035import org.opencms.file.types.CmsResourceTypeXmlContainerPage; 036import org.opencms.i18n.CmsLocaleManager; 037import org.opencms.loader.CmsLoaderException; 038import org.opencms.main.CmsException; 039import org.opencms.main.CmsLog; 040import org.opencms.main.OpenCms; 041import org.opencms.search.I_CmsSearchDocument; 042import org.opencms.search.fields.CmsSearchField; 043import org.opencms.search.fields.CmsSearchFieldConfiguration; 044import org.opencms.util.CmsStringUtil; 045import org.opencms.util.CmsUUID; 046 047import java.util.ArrayList; 048import java.util.Arrays; 049import java.util.Date; 050import java.util.List; 051import java.util.Locale; 052import java.util.Map; 053 054import org.apache.commons.logging.Log; 055 056/** 057 * Contains a single search result from the gallery search index.<p> 058 * 059 * @since 8.0.0 060 */ 061/** 062 * 063 */ 064public class CmsGallerySearchResult implements Comparable<CmsGallerySearchResult> { 065 066 /** The logger instance for this class. */ 067 public static final Log LOG = CmsLog.getLog(CmsGallerySearchResult.class); 068 069 /** List of Solr fields that are read during the initialization of the search result. */ 070 private static String[] m_requiredSolrFields; 071 072 /** The additional information for the gallery search index. */ 073 protected String m_additonalInfo; 074 075 /** The supported container types of this search result. */ 076 protected List<String> m_containerTypes; 077 078 /** The creation date of this search result. */ 079 protected Date m_dateCreated; 080 081 /** The expiration date of this search result. */ 082 protected Date m_dateExpired; 083 084 /** The last modification date of this search result. */ 085 protected Date m_dateLastModified; 086 087 /** The release date of this search result. */ 088 protected Date m_dateReleased; 089 090 /** The description of this search result. */ 091 protected String m_description; 092 093 /** The excerpt of this search result. */ 094 protected String m_excerpt; 095 096 /** The length of the search result. */ 097 protected int m_length; 098 099 /** The locales in which the content is available. */ 100 protected List<String> m_locales; 101 102 /** The resource path of this search result. */ 103 protected String m_path; 104 105 /** The resource type of the search result. */ 106 protected String m_resourceType; 107 108 /** The score of this search result. */ 109 protected int m_score; 110 111 /** The state of the search result. */ 112 protected int m_state; 113 114 /** The structure UUID of the resource. */ 115 protected String m_structureId; 116 117 /** The title of this search result. */ 118 protected String m_title; 119 120 /** The user who created the search result resource. */ 121 protected String m_userCreated; 122 123 /** The user who last modified the search result resource. */ 124 protected String m_userLastModified; 125 126 /** 127 * Creates a fake gallery search result by reading the necessary data from a VFS resource.<p> 128 * 129 * @param cms the current CMS context 130 * @param res the resource from which the data should be read 131 */ 132 public CmsGallerySearchResult(CmsObject cms, CmsResource res) { 133 134 try { 135 Map<String, String> props = CmsProperty.toMap( 136 cms.readPropertyObjects(res, CmsResourceTypeXmlContainerPage.isContainerPage(res))); 137 m_title = props.get(CmsPropertyDefinition.PROPERTY_TITLE); 138 m_description = props.get(CmsPropertyDefinition.PROPERTY_DESCRIPTION); 139 } catch (CmsException e) { 140 LOG.error(e.getLocalizedMessage(), e); 141 } 142 if (m_description == null) { 143 m_description = ""; 144 } 145 if (m_title == null) { 146 m_title = res.getName(); 147 } 148 m_dateCreated = new Date(res.getDateCreated()); 149 m_dateExpired = new Date(res.getDateExpired()); 150 m_dateLastModified = new Date(res.getDateLastModified()); 151 m_dateReleased = new Date(res.getDateReleased()); 152 m_length = res.getLength(); 153 m_locales = null; 154 m_path = res.getRootPath(); 155 try { 156 m_resourceType = OpenCms.getResourceManager().getResourceType(res.getTypeId()).getTypeName(); 157 } catch (CmsLoaderException e) { 158 LOG.warn(e.getLocalizedMessage(), e); 159 } 160 m_state = res.getState().getState(); 161 m_structureId = res.getStructureId().toString(); 162 try { 163 m_userCreated = cms.readUser(res.getUserCreated()).getFullName(); 164 } catch (CmsException e) { 165 LOG.warn(e.getLocalizedMessage(), e); 166 } 167 try { 168 m_userLastModified = cms.readUser(res.getUserLastModified()).getFullName(); 169 } catch (CmsException e) { 170 LOG.warn(e.getLocalizedMessage(), e); 171 } 172 } 173 174 /** 175 * Creates a new gallery search result. 176 * 177 * @param cms the current CMS context (used for reading information missing from the index) 178 * @param doc the I_CmsSearchResult document to extract information from. 179 * @param score the score of this search result 180 * @param locale the locale to create the result for 181 */ 182 public CmsGallerySearchResult(I_CmsSearchDocument doc, CmsObject cms, int score, Locale locale) { 183 184 if (null == doc) { 185 throw new IllegalArgumentException(); 186 } 187 188 if (doc.getType().equals(CmsResourceTypeFunctionConfig.TYPE_NAME)) { 189 locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms); 190 } 191 192 m_score = score; //(int)doc.getScore(); 193 194 m_path = doc.getFieldValueAsString(CmsSearchField.FIELD_PATH); 195 196 if (null == locale) { 197 OpenCms.getLocaleManager(); 198 locale = CmsLocaleManager.getDefaultLocale(); 199 } 200 201 // For title and description, try various fields and use the first which is not empty 202 203 String mainTitleField = CmsSearchFieldConfiguration.getLocaleExtendedName( 204 CmsSearchField.FIELD_TITLE_UNSTORED, 205 locale.toString()) + "_s"; 206 String localizedTitlePropertyField = CmsSearchFieldConfiguration.getLocaleExtendedName( 207 CmsPropertyDefinition.PROPERTY_TITLE, 208 locale.toString()) + CmsSearchField.FIELD_DYNAMIC_PROPERTIES_DIRECT + "_s"; 209 String titlePropertyField = CmsPropertyDefinition.PROPERTY_TITLE 210 + CmsSearchField.FIELD_DYNAMIC_PROPERTIES_DIRECT 211 + "_s"; 212 213 for (String fieldName : Arrays.asList(mainTitleField, localizedTitlePropertyField, titlePropertyField)) { 214 m_title = doc.getFieldValueAsString(fieldName); 215 if (!CmsStringUtil.isEmptyOrWhitespaceOnly(m_title)) { 216 break; 217 } 218 } 219 220 String mainDescField = CmsSearchFieldConfiguration.getLocaleExtendedName( 221 CmsSearchField.FIELD_DESCRIPTION, 222 locale.toString()) + "_s"; 223 String localizedDescPropertyField = CmsSearchFieldConfiguration.getLocaleExtendedName( 224 CmsPropertyDefinition.PROPERTY_DESCRIPTION, 225 locale.toString()) + CmsSearchField.FIELD_DYNAMIC_PROPERTIES + "_s"; 226 String descPropertyField = CmsPropertyDefinition.PROPERTY_DESCRIPTION 227 + CmsSearchField.FIELD_DYNAMIC_PROPERTIES 228 + "_s"; 229 230 for (String fieldName : Arrays.asList(mainDescField, localizedDescPropertyField, descPropertyField)) { 231 m_description = doc.getFieldValueAsString(fieldName); 232 if (!CmsStringUtil.isEmptyOrWhitespaceOnly(m_description)) { 233 break; 234 } 235 } 236 237 m_resourceType = doc.getFieldValueAsString(CmsSearchField.FIELD_TYPE); 238 239 m_dateCreated = doc.getFieldValueAsDate(CmsSearchField.FIELD_DATE_CREATED); 240 241 m_dateLastModified = doc.getFieldValueAsDate(CmsSearchField.FIELD_DATE_LASTMODIFIED); 242 243 m_dateExpired = doc.getFieldValueAsDate(CmsSearchField.FIELD_DATE_EXPIRED); 244 245 m_dateReleased = doc.getFieldValueAsDate(CmsSearchField.FIELD_DATE_RELEASED); 246 247 m_length = 0; 248 final String s_length = doc.getFieldValueAsString(CmsSearchField.FIELD_SIZE); 249 if (null != s_length) { 250 try { 251 m_length = Integer.parseInt(s_length); 252 } catch (NumberFormatException exc) { 253 // NOOP, default is 0 254 } 255 } 256 257 m_state = 0; 258 final String s_state = doc.getFieldValueAsString(CmsSearchField.FIELD_STATE); 259 if (s_state != null) { 260 try { 261 m_state = Integer.parseInt(s_state); 262 } catch (NumberFormatException exc) { 263 // NOOP, default is 0 264 } 265 } 266 267 m_userCreated = doc.getFieldValueAsString(CmsSearchField.FIELD_USER_CREATED); 268 269 m_structureId = doc.getFieldValueAsString(CmsSearchField.FIELD_ID); 270 271 m_userLastModified = doc.getFieldValueAsString(CmsSearchField.FIELD_USER_LAST_MODIFIED); 272 273 m_additonalInfo = doc.getFieldValueAsString(CmsSearchField.FIELD_ADDITIONAL_INFO); 274 final String s_containerTypes = doc.getFieldValueAsString(CmsSearchField.FIELD_CONTAINER_TYPES); 275 if (s_containerTypes != null) { 276 m_containerTypes = CmsStringUtil.splitAsList(s_containerTypes, ' '); 277 } else { 278 m_containerTypes = new ArrayList<String>(0); 279 } 280 281 final String s_locales = doc.getFieldValueAsString(CmsSearchField.FIELD_RESOURCE_LOCALES); 282 if (null != s_locales) { 283 m_locales = CmsStringUtil.splitAsList(s_locales, ' '); 284 } else { 285 m_locales = new ArrayList<String>(0); 286 } 287 288 if ((null != cms) && (null != m_structureId)) { 289 initializeMissingFieldsFromVfs(cms, new CmsUUID(m_structureId)); 290 } 291 } 292 293 /** 294 * Returns the list of Solr fields a search result must have to initialize the gallery search result correctly. 295 * @return the list of Solr fields. 296 */ 297 public static final String[] getRequiredSolrFields() { 298 299 if (null == m_requiredSolrFields) { 300 List<Locale> locales = OpenCms.getLocaleManager().getAvailableLocales(); 301 m_requiredSolrFields = new String[14 + (locales.size() * 6)]; 302 int count = 0; 303 m_requiredSolrFields[count++] = CmsSearchField.FIELD_PATH; 304 m_requiredSolrFields[count++] = CmsSearchField.FIELD_TYPE; 305 m_requiredSolrFields[count++] = CmsSearchField.FIELD_DATE_CREATED; 306 m_requiredSolrFields[count++] = CmsSearchField.FIELD_DATE_LASTMODIFIED; 307 m_requiredSolrFields[count++] = CmsSearchField.FIELD_DATE_EXPIRED; 308 m_requiredSolrFields[count++] = CmsSearchField.FIELD_DATE_RELEASED; 309 m_requiredSolrFields[count++] = CmsSearchField.FIELD_SIZE; 310 m_requiredSolrFields[count++] = CmsSearchField.FIELD_STATE; 311 m_requiredSolrFields[count++] = CmsSearchField.FIELD_USER_CREATED; 312 m_requiredSolrFields[count++] = CmsSearchField.FIELD_ID; 313 m_requiredSolrFields[count++] = CmsSearchField.FIELD_USER_LAST_MODIFIED; 314 m_requiredSolrFields[count++] = CmsSearchField.FIELD_ADDITIONAL_INFO; 315 m_requiredSolrFields[count++] = CmsSearchField.FIELD_CONTAINER_TYPES; 316 m_requiredSolrFields[count++] = CmsSearchField.FIELD_RESOURCE_LOCALES; 317 for (Locale locale : locales) { 318 m_requiredSolrFields[count++] = CmsSearchFieldConfiguration.getLocaleExtendedName( 319 CmsSearchField.FIELD_TITLE_UNSTORED, 320 locale.toString()) + "_s"; 321 m_requiredSolrFields[count++] = CmsSearchFieldConfiguration.getLocaleExtendedName( 322 CmsPropertyDefinition.PROPERTY_TITLE, 323 locale.toString()) + CmsSearchField.FIELD_DYNAMIC_PROPERTIES_DIRECT + "_s"; 324 m_requiredSolrFields[count++] = CmsPropertyDefinition.PROPERTY_TITLE 325 + CmsSearchField.FIELD_DYNAMIC_PROPERTIES_DIRECT 326 + "_s"; 327 m_requiredSolrFields[count++] = CmsSearchFieldConfiguration.getLocaleExtendedName( 328 CmsSearchField.FIELD_DESCRIPTION, 329 locale.toString()) + "_s"; 330 m_requiredSolrFields[count++] = CmsSearchFieldConfiguration.getLocaleExtendedName( 331 CmsPropertyDefinition.PROPERTY_DESCRIPTION, 332 locale.toString()) + CmsSearchField.FIELD_DYNAMIC_PROPERTIES + "_s"; 333 m_requiredSolrFields[count++] = CmsPropertyDefinition.PROPERTY_DESCRIPTION 334 + CmsSearchField.FIELD_DYNAMIC_PROPERTIES 335 + "_s"; 336 } 337 } 338 return m_requiredSolrFields; 339 } 340 341 /** 342 * Compares two search results based on the score of the result.<p> 343 * 344 * @param other the result to compare this result with 345 * @return the comparison result 346 * 347 * @see java.lang.Comparable#compareTo(java.lang.Object) 348 */ 349 public int compareTo(CmsGallerySearchResult other) { 350 351 if (other == this) { 352 return 0; 353 } 354 return other.m_score - m_score; 355 } 356 357 /** 358 * @see java.lang.Object#equals(java.lang.Object) 359 */ 360 @Override 361 public boolean equals(Object obj) { 362 363 if (obj == this) { 364 return true; 365 } 366 if (obj instanceof CmsGallerySearchResult) { 367 CmsGallerySearchResult other = (CmsGallerySearchResult)obj; 368 return m_path.equals(other.m_path); 369 } 370 return false; 371 } 372 373 /** 374 * Returns the additional information stored for this search result in the gallery search index.<p> 375 * 376 * @return the additional information stored for this search result in the gallery search index 377 */ 378 public String getAdditonalInfo() { 379 380 return m_additonalInfo; 381 } 382 383 /** 384 * Returns the containers supported by this resource.<p> 385 * 386 * @return the containers supported by this resource 387 */ 388 public List<String> getContainerTypes() { 389 390 return m_containerTypes; 391 } 392 393 /** 394 * Returns the date created.<p> 395 * 396 * @return the date created 397 */ 398 public Date getDateCreated() { 399 400 return m_dateCreated; 401 } 402 403 /** 404 * Returns the date the resource expires.<p> 405 * 406 * @return the date the resource expires 407 * 408 * @see org.opencms.file.CmsResource#getDateExpired() 409 */ 410 public Date getDateExpired() { 411 412 return m_dateExpired; 413 } 414 415 /** 416 * Returns the date last modified.<p> 417 * 418 * @return the date last modified 419 */ 420 public Date getDateLastModified() { 421 422 return m_dateLastModified; 423 } 424 425 /** 426 * Returns the date the resource is released.<p> 427 * 428 * @return the date the resource is released 429 * 430 * @see org.opencms.file.CmsResource#getDateReleased() 431 */ 432 public Date getDateReleased() { 433 434 return m_dateReleased; 435 } 436 437 /** 438 * Returns the description.<p> 439 * 440 * @return the description 441 */ 442 public String getDescription() { 443 444 return m_description; 445 } 446 447 /** 448 * Returns the excerpt.<p> 449 * 450 * @return the excerpt 451 */ 452 public String getExcerpt() { 453 454 return m_excerpt; 455 } 456 457 /** 458 * Returns the length of the resource.<p> 459 * 460 * @return the length of the resource 461 * 462 * @see org.opencms.file.CmsResource#getLength() 463 */ 464 public int getLength() { 465 466 return m_length; 467 } 468 469 /** 470 * Returns the list of locales this search result is available for.<p> 471 * 472 * @return the list of locales this search result is available for 473 */ 474 public List<String> getLocales() { 475 476 return m_locales; 477 } 478 479 /** 480 * Returns the resource root path.<p> 481 * 482 * @return the resource root path 483 * 484 * @see org.opencms.file.CmsResource#getRootPath() 485 */ 486 public String getPath() { 487 488 return m_path; 489 } 490 491 /** 492 * Returns the resource type of the search result document.<p> 493 * 494 * @return the resource type of the search result document 495 * 496 * @see org.opencms.loader.CmsResourceManager#getResourceType(String) 497 */ 498 public String getResourceType() { 499 500 return m_resourceType; 501 } 502 503 /** 504 * Returns the Lucene search score for this result.<p> 505 * 506 * @return the Lucene search score for this result 507 */ 508 public int getScore() { 509 510 return m_score; 511 } 512 513 /** 514 * Returns the state of the resource.<p> 515 * 516 * @return the state of the resource 517 * 518 * @see org.opencms.file.CmsResource#getState() 519 */ 520 public int getState() { 521 522 return m_state; 523 } 524 525 /** 526 * Returns the structure id of the resource.<p> 527 * 528 * @return the structure id of the resource 529 */ 530 public String getStructureId() { 531 532 return m_structureId; 533 } 534 535 /** 536 * Returns the title of the resource.<p> 537 * 538 * @return the title of the resource 539 */ 540 public String getTitle() { 541 542 return m_title; 543 } 544 545 /** 546 * Returns the name of the user who created the resource.<p> 547 * 548 * @return the name of the user who created the resource 549 * 550 * @see org.opencms.file.CmsResource#getUserCreated() 551 */ 552 public String getUserCreated() { 553 554 return m_userCreated; 555 } 556 557 /** 558 * Returns the name of the user who last modified the resource.<p> 559 * 560 * @return the name of the user who last modified the resource 561 * 562 * @see org.opencms.file.CmsResource#getUserLastModified() 563 */ 564 public String getUserLastModified() { 565 566 return m_userLastModified; 567 } 568 569 /** 570 * @see java.lang.Object#hashCode() 571 */ 572 @Override 573 public int hashCode() { 574 575 return m_path.hashCode(); 576 } 577 578 /** 579 * Returns if the related resource is released and not expired.<p> 580 * 581 * @param cms the cms context 582 * 583 * @return <code>true</code> if the related resource is released and not expired 584 */ 585 public boolean isReleaseAndNotExpired(CmsObject cms) { 586 587 long time = cms.getRequestContext().getRequestTime(); 588 return (time == CmsResource.DATE_RELEASED_EXPIRED_IGNORE) 589 || ((time > m_dateReleased.getTime()) && (time < m_dateExpired.getTime())); 590 } 591 592 /** 593 * Initializes missing fields by reading the information from the VFS.<p> 594 * 595 * @param cms the current CMS context 596 * @param structureId the current structure id 597 */ 598 protected void initializeMissingFieldsFromVfs(CmsObject cms, CmsUUID structureId) { 599 600 if (structureId == null) { 601 return; 602 } 603 if ((m_title != null) && (m_description != null)) { 604 return; 605 } 606 607 try { 608 CmsResource res = cms.readResource(structureId); 609 if (m_description == null) { 610 CmsProperty descProp = cms.readPropertyObject( 611 res, 612 CmsPropertyDefinition.PROPERTY_DESCRIPTION, 613 CmsResourceTypeXmlContainerPage.isContainerPage(res)); 614 m_description = descProp.getValue(); 615 } 616 617 if (m_title == null) { 618 CmsProperty titleProp = cms.readPropertyObject( 619 res, 620 CmsPropertyDefinition.PROPERTY_TITLE, 621 CmsResourceTypeXmlContainerPage.isContainerPage(res)); 622 m_title = titleProp.getValue(); 623 if (CmsStringUtil.isEmptyOrWhitespaceOnly(m_title)) { 624 m_title = res.getName(); 625 } 626 } 627 } catch (CmsException e) { 628 LOG.error(e.getLocalizedMessage(), e); 629 return; 630 } 631 } 632}