001/* 002 * Copyright 2025 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.cms.search.systemprop; 017 018import java.util.ArrayList; 019import java.util.Collection; 020import java.util.List; 021 022import org.apache.solr.common.SolrInputDocument; 023 024import org.ametys.cms.data.ametysobject.IndexableAmetysObject; 025import org.ametys.cms.data.type.indexing.IndexableElementType; 026import org.ametys.cms.model.CMSDataContext; 027import org.ametys.cms.model.properties.AbstractIndexableStaticProperty; 028import org.ametys.cms.search.solr.schema.CopyFieldDefinition; 029import org.ametys.cms.search.solr.schema.FieldDefinition; 030import org.ametys.cms.search.solr.schema.SchemaDefinition; 031 032/** 033 * Abstract class for single indexation aware system property 034 * @param <T> type of the property values 035 * @param <C> type of criterion 036 * @param <X> type of ametys object supported by this property 037 */ 038public abstract class AbstractIndexableSystemProperty<T, C, X extends IndexableAmetysObject> extends AbstractIndexableStaticProperty<T, C, X> implements IndexationAwareSystemProperty<T, X> 039{ 040 @Override 041 protected String _getNameConfigurationAttribute() 042 { 043 return "id"; 044 } 045 046 @Override 047 public void indexValue(SolrInputDocument document, X ametysObject, CMSDataContext context) 048 { 049 String solrFieldName = getSolrFieldName(); 050 if (solrFieldName == null) 051 { 052 // Nothing to index 053 return; 054 } 055 056 String solrSortFieldName = getSolrSortFieldName(); 057 boolean indexSortableField = isSortable() && solrSortFieldName != null && !solrFieldName.equals(solrSortFieldName); 058 059 IndexableElementType<T> type = getType(); 060 Object value = getValue(ametysObject); 061 062 if (value == null 063 || type.getManagedClassArray().isInstance(value) && type.getManagedClassArray().cast(value).length == 0) 064 { 065 // Add empty value in document in order to remove the value during partial indexing 066 document.addField(solrFieldName, null); 067 068 if (indexSortableField) 069 { 070 document.addField(solrSortFieldName, null); 071 } 072 } 073 else 074 { 075 if (type.getManagedClass().isInstance(value)) 076 { 077 Object valueToIndex = type.getSingleValueToIndex(type.getManagedClass().cast(value)); 078 document.addField(solrFieldName, valueToIndex); 079 } 080 else if (type.getManagedClassArray().isInstance(value)) 081 { 082 T[] values = type.getManagedClassArray().cast(value); 083 for (T singleValue : values) 084 { 085 Object valueToIndex = type.getSingleValueToIndex(singleValue); 086 document.addField(solrFieldName, valueToIndex); 087 } 088 } 089 090 // Index sort field 091 Object sortValue = getSortValue(ametysObject); 092 if (indexSortableField && sortValue != null) 093 { 094 document.setField(solrSortFieldName, sortValue); 095 } 096 } 097 } 098 099 /** 100 * Get the sort value represented by this field in the given result ametys object. 101 * @param ametysObject the result ametys object. 102 * @return the content sort value, must be scalar (String, long, double, Date). 103 */ 104 protected Object getSortValue(X ametysObject) 105 { 106 Object value = getValue(ametysObject); 107 if (value == null) 108 { 109 return null; 110 } 111 112 IndexableElementType<T> type = getType(); 113 if (type.getManagedClassArray().isInstance(value)) 114 { 115 T[] values = type.getManagedClassArray().cast(value); 116 return values.length > 0 ? values[0] : value; 117 } 118 else 119 { 120 return value; 121 } 122 } 123 124 public Collection<SchemaDefinition> getSchemaDefinitions() 125 { 126 List<SchemaDefinition> definitions = new ArrayList<>(); 127 128 String solrFieldName = getSolrFieldName(); 129 String sortFieldName = getSolrSortFieldName(); 130 String facetFieldName = getSolrFacetFieldName(); 131 132 boolean multiple = isMultiple(); 133 String type = getType().getSchemaType(); 134 if (solrFieldName != null && type != null) 135 { 136 definitions.add(new FieldDefinition(solrFieldName, type, multiple, false)); 137 138 if (sortFieldName != null && !sortFieldName.equals(solrFieldName)) 139 { 140 definitions.add(new FieldDefinition(sortFieldName, type, false, false)); 141 } 142 143 if (facetFieldName != null && !facetFieldName.equals(solrFieldName)) 144 { 145 // By default the index value in field name will be automatically copy in facet field 146 // So we do not need the index facet field manually 147 definitions.add(new FieldDefinition(facetFieldName, type, multiple, true)); 148 definitions.add(new CopyFieldDefinition(solrFieldName, facetFieldName)); 149 } 150 } 151 152 return definitions; 153 } 154 155 /** 156 * Get the value as a array of String 157 * @param value The value as an object to parse 158 * @return The values as a String array 159 */ 160 protected String[] parseStringArray(Object value) 161 { 162 return value instanceof String 163 ? new String[] {(String) value} 164 : (String[]) value; 165 } 166}