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.apache.commons.logging.Log; 035import org.apache.solr.common.SolrDocument; 036import org.apache.solr.common.SolrException; 037import org.apache.solr.common.SolrInputDocument; 038import org.apache.solr.schema.*; 039import org.opencms.file.CmsObject; 040import org.opencms.file.CmsResource; 041import org.opencms.main.CmsLog; 042import org.opencms.main.OpenCms; 043import org.opencms.relations.CmsCategory; 044import org.opencms.search.CmsSearchUtil; 045import org.opencms.search.I_CmsSearchDocument; 046import org.opencms.search.documents.CmsDocumentDependency; 047import org.opencms.search.fields.CmsSearchField; 048import org.opencms.util.CmsStringUtil; 049import org.opencms.util.CmsUUID; 050 051import java.nio.ByteBuffer; 052import java.text.ParseException; 053import java.util.*; 054 055/** 056 * A search document implementation for Solr indexes.<p> 057 * 058 * @since 8.5.0 059 */ 060public class CmsSolrDocument implements I_CmsSearchDocument { 061 062 /** The log object for this class. */ 063 private static final Log LOG = CmsLog.getLog(CmsSolrDocument.class); 064 065 /** The Solr document. */ 066 private SolrInputDocument m_doc; 067 068 /** Holds the score for this document. */ 069 private float m_score; 070 071 /** 072 * Public constructor to create a encapsulate a Solr document.<p> 073 * 074 * @param doc the Solr document 075 */ 076 public CmsSolrDocument(SolrDocument doc) { 077 078 this(); 079 m_doc = CmsSearchUtil.toSolrInputDocument(doc); 080 } 081 082 /** 083 * Public constructor to create a encapsulate a Solr document.<p> 084 * 085 * @param doc the Solr document 086 */ 087 public CmsSolrDocument(SolrInputDocument doc) { 088 089 this(); 090 m_doc = doc; 091 } 092 093 /** 094 * Private constructor.<p> 095 */ 096 private CmsSolrDocument() { 097 098 } 099 100 /** 101 * @see org.opencms.search.I_CmsSearchDocument#addCategoryField(java.util.List) 102 */ 103 public void addCategoryField(List<CmsCategory> categories) { 104 105 if ((categories != null) && (categories.size() > 0)) { 106 for (CmsCategory category : categories) { 107 m_doc.addField(CmsSearchField.FIELD_CATEGORY, category.getPath()); 108 } 109 } 110 } 111 112 /** 113 * @see org.opencms.search.I_CmsSearchDocument#addContentField(byte[]) 114 */ 115 public void addContentField(byte[] data) { 116 117 m_doc.setField(CmsSearchField.FIELD_CONTENT_BLOB, ByteBuffer.wrap(data)); 118 } 119 120 /** 121 * @see org.opencms.search.I_CmsSearchDocument#addContentLocales(java.util.Collection) 122 */ 123 public void addContentLocales(Collection<Locale> locales) { 124 125 if ((locales != null) && !locales.isEmpty()) { 126 for (Locale locale : locales) { 127 m_doc.addField(CmsSearchField.FIELD_CONTENT_LOCALES, locale.toString()); 128 } 129 } 130 } 131 132 /** 133 * @see org.opencms.search.I_CmsSearchDocument#addDateField(java.lang.String, long, boolean) 134 */ 135 public void addDateField(String name, long time, boolean analyzed) { 136 137 String val = CmsSearchUtil.getDateAsIso8601(time); 138 m_doc.addField(name, val); 139 if (analyzed) { 140 m_doc.addField(name + CmsSearchField.FIELD_DATE_LOOKUP_SUFFIX, val); 141 } 142 } 143 144 /** 145 * Adds the given document dependency to this document.<p> 146 * 147 * @param cms the current CmsObject 148 * @param resDeps the dependency 149 */ 150 public void addDocumentDependency(CmsObject cms, CmsDocumentDependency resDeps) { 151 152 if (resDeps != null) { 153 m_doc.addField(CmsSearchField.FIELD_DEPENDENCY_TYPE, resDeps.getType()); 154 if ((resDeps.getMainDocument() != null) && (resDeps.getType() != null)) { 155 m_doc.addField( 156 CmsSearchField.FIELD_PREFIX_DEPENDENCY + resDeps.getType().toString(), 157 resDeps.getMainDocument().toDependencyString(cms)); 158 } 159 for (CmsDocumentDependency dep : resDeps.getVariants()) { 160 m_doc.addField( 161 CmsSearchField.FIELD_PREFIX_DEPENDENCY + dep.getType().toString(), 162 dep.toDependencyString(cms)); 163 } 164 for (CmsDocumentDependency dep : resDeps.getAttachments()) { 165 m_doc.addField( 166 CmsSearchField.FIELD_PREFIX_DEPENDENCY + dep.getType().toString(), 167 dep.toDependencyString(cms)); 168 } 169 } 170 } 171 172 /** 173 * @see org.opencms.search.I_CmsSearchDocument#addFileSizeField(int) 174 */ 175 public void addFileSizeField(int length) { 176 177 if (OpenCms.getSearchManager().getSolrServerConfiguration().getSolrSchema().hasExplicitField( 178 CmsSearchField.FIELD_SIZE)) { 179 m_doc.addField(CmsSearchField.FIELD_SIZE, Integer.valueOf(length)); 180 } 181 } 182 183 /** 184 * Adds a multi-valued field.<p> 185 * 186 * @param fieldName the field name to put the values in 187 * @param values the values to put in the field 188 */ 189 public void addMultiValuedField(String fieldName, List<String> values) { 190 191 if ((values != null) && (values.size() > 0)) { 192 for (String value : values) { 193 m_doc.addField(fieldName, value); 194 } 195 } 196 } 197 198 /** 199 * @see org.opencms.search.I_CmsSearchDocument#addPathField(java.lang.String) 200 */ 201 public void addPathField(String rootPath) { 202 203 String folderName = CmsResource.getFolderPath(rootPath); 204 for (int i = 0; i < folderName.length(); i++) { 205 char c = folderName.charAt(i); 206 if (c == '/') { 207 m_doc.addField(CmsSearchField.FIELD_PARENT_FOLDERS, folderName.substring(0, i + 1)); 208 } 209 } 210 } 211 212 /** 213 * @see org.opencms.search.I_CmsSearchDocument#addResourceLocales(java.util.Collection) 214 */ 215 public void addResourceLocales(Collection<Locale> locales) { 216 217 if ((locales != null) && !locales.isEmpty()) { 218 for (Locale locale : locales) { 219 m_doc.addField(CmsSearchField.FIELD_RESOURCE_LOCALES, locale.toString()); 220 } 221 } 222 } 223 224 /** 225 * @see org.opencms.search.I_CmsSearchDocument#addRootPathField(java.lang.String) 226 */ 227 public void addRootPathField(String rootPath) { 228 229 m_doc.addField(CmsSearchField.FIELD_PATH, rootPath); 230 } 231 232 /** 233 * @see org.opencms.search.I_CmsSearchDocument#addSearchField(org.opencms.search.fields.CmsSearchField, java.lang.String) 234 */ 235 public void addSearchField(CmsSearchField sfield, String value) { 236 237 CmsSolrField field = (CmsSolrField)sfield; 238 List<String> fieldsToAdd = new ArrayList<String>(Collections.singletonList(field.getName())); 239 if ((field.getCopyFields() != null) && !field.getCopyFields().isEmpty()) { 240 fieldsToAdd.addAll(field.getCopyFields()); 241 } 242 IndexSchema schema = OpenCms.getSearchManager().getSolrServerConfiguration().getSolrSchema(); 243 for (String fieldName : fieldsToAdd) { 244 try { 245 List<String> splitedValues = new ArrayList<String>(); 246 boolean multi = false; 247 248 try { 249 SchemaField f = schema.getField(fieldName); 250 if ((f != null) && (!field.getName().startsWith(CmsSearchField.FIELD_CONTENT))) { 251 multi = f.multiValued(); 252 } 253 } catch (@SuppressWarnings("unused") SolrException e) { 254 LOG.warn(Messages.get().getBundle().key(Messages.LOG_SOLR_FIELD_NOT_FOUND_1, field.toString())); 255 } 256 if (multi) { 257 splitedValues = CmsStringUtil.splitAsList(value.toString(), "\n"); 258 } else { 259 splitedValues.add(value); 260 } 261 for (String val : splitedValues) { 262 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(val)) { 263 try { 264 FieldType fieldType = schema.getFieldType(fieldName); 265 if (fieldType instanceof DatePointField) { 266 //sometime,the val is already Iso8601 formated 267 if(!val.contains("Z")) 268 val = CmsSearchUtil.getDateAsIso8601(Long.valueOf(val).longValue()); 269 } 270 } catch (SolrException e) { 271 LOG.debug(e.getMessage(), e); 272 throw new RuntimeException(e); 273 } 274 if (fieldName.endsWith(CmsSearchField.FIELD_EXCERPT)) { 275 // TODO: make the length and the area configurable 276 val = CmsStringUtil.trimToSize(val, 1000, 50, ""); 277 } 278 m_doc.addField(fieldName, val); 279 } 280 } 281 } catch (SolrException e) { 282 LOG.error(e.getMessage(), e); 283 } catch (@SuppressWarnings("unused") RuntimeException e) { 284 // noop 285 } 286 } 287 } 288 289 /** 290 * @see org.opencms.search.I_CmsSearchDocument#addSuffixField(java.lang.String) 291 */ 292 public void addSuffixField(String suffix) { 293 294 m_doc.addField(CmsSearchField.FIELD_SUFFIX, suffix); 295 } 296 297 /** 298 * @see org.opencms.search.I_CmsSearchDocument#addTypeField(java.lang.String) 299 */ 300 public void addTypeField(String type) { 301 302 m_doc.addField(CmsSearchField.FIELD_TYPE, type); 303 } 304 305 /** 306 * @see org.opencms.search.I_CmsSearchDocument#getContentBlob() 307 */ 308 public byte[] getContentBlob() { 309 310 Object o = m_doc.getFieldValue(CmsSearchField.FIELD_CONTENT_BLOB); 311 if (o != null) { 312 if (o instanceof byte[]) { 313 return (byte[])o; 314 } 315 return o.toString().getBytes(); 316 } 317 return null; 318 } 319 320 /** 321 * @see org.opencms.search.I_CmsSearchDocument#getDocument() 322 */ 323 public Object getDocument() { 324 325 return m_doc; 326 } 327 328 /** 329 * @see org.opencms.search.I_CmsSearchDocument#getFieldNames() 330 */ 331 public List<String> getFieldNames() { 332 333 return new ArrayList<String>(m_doc.getFieldNames()); 334 } 335 336 /** 337 * @see org.opencms.search.I_CmsSearchDocument#getFieldValueAsDate(java.lang.String) 338 */ 339 public Date getFieldValueAsDate(String fieldName) { 340 341 Object o = m_doc.getFieldValue(fieldName); 342 if (o instanceof Date) { 343 return (Date)o; 344 } 345 if (o != null) { 346 try { 347 return CmsSearchUtil.parseDate(o.toString()); 348 } catch (ParseException e) { 349 // ignore: not a valid date format 350 LOG.debug(e.getLocalizedMessage(), e); 351 } 352 } 353 return null; 354 } 355 356 /** 357 * @see org.opencms.search.I_CmsSearchDocument#getFieldValueAsString(java.lang.String) 358 */ 359 public String getFieldValueAsString(String fieldName) { 360 361 List<String> values = getMultivaluedFieldAsStringList(fieldName); 362 if ((values != null) && !values.isEmpty()) { 363 return CmsStringUtil.listAsString(values, "\n"); 364 } else { 365 Object o = m_doc.getFieldValue(fieldName); 366 if (o != null) { 367 return o.toString(); 368 } 369 } 370 return null; 371 } 372 373 /** 374 * @see org.opencms.search.I_CmsSearchDocument#getMultivaluedFieldAsStringList(java.lang.String) 375 */ 376 public List<String> getMultivaluedFieldAsStringList(String fieldName) { 377 378 List<String> result = new ArrayList<String>(); 379 Collection<Object> coll = m_doc.getFieldValues(fieldName); 380 if (coll != null) { 381 for (Object o : coll) { 382 if (o != null) { 383 result.add(o.toString()); 384 } 385 } 386 return result; 387 } 388 return null; 389 } 390 391 /** 392 * @see org.opencms.search.I_CmsSearchDocument#getPath() 393 */ 394 public String getPath() { 395 396 return getFieldValueAsString(CmsSearchField.FIELD_PATH); 397 } 398 399 /** 400 * @see org.opencms.search.I_CmsSearchDocument#getScore() 401 */ 402 public float getScore() { 403 404 Float score = (Float)getSolrDocument().getFirstValue(CmsSearchField.FIELD_SCORE); 405 if (score != null) { 406 m_score = score.floatValue(); 407 return m_score; 408 } 409 return 0F; 410 } 411 412 /** 413 * Returns the Solr document.<p> 414 * 415 * @return the Solr document 416 */ 417 public SolrDocument getSolrDocument() { 418 419 return CmsSearchUtil.toSolrDocument(m_doc); 420 } 421 422 /** 423 * @see org.opencms.search.I_CmsSearchDocument#getType() 424 */ 425 public String getType() { 426 427 return getFieldValueAsString(CmsSearchField.FIELD_TYPE); 428 } 429 430 431 /** 432 * Sets the id of this document.<p> 433 * 434 * @param structureId the structure id to use 435 */ 436 public void setId(CmsUUID structureId) { 437 438 m_doc.addField(CmsSearchField.FIELD_ID, structureId.toString()); 439 440 } 441 442 /** 443 * @see org.opencms.search.I_CmsSearchDocument#setScore(float) 444 */ 445 public void setScore(float score) { 446 447 m_score = score; 448 } 449 450 /** 451 * @see java.lang.Object#toString() 452 */ 453 @Override 454 public String toString() { 455 456 return getFieldValueAsString(CmsSearchField.FIELD_PATH); 457 } 458}