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 Object value = getValue(ametysObject); 057 if (value == null) 058 { 059 // Add empty value in document in order to remove the value during partial indexing 060 document.addField(solrFieldName, null); 061 } 062 063 IndexableElementType<T> type = getType(); 064 if (type.getManagedClass().isInstance(value)) 065 { 066 Object valueToIndex = type.getSingleValueToIndex(type.getManagedClass().cast(value)); 067 document.addField(solrFieldName, valueToIndex); 068 } 069 else if (type.getManagedClassArray().isInstance(value)) 070 { 071 T[] values = type.getManagedClassArray().cast(value); 072 if (values.length == 0) 073 { 074 // Add empty value in document in order to remove the value during partial indexing 075 document.addField(solrFieldName, null); 076 } 077 078 for (T singleValue : values) 079 { 080 Object valueToIndex = type.getSingleValueToIndex(singleValue); 081 document.addField(solrFieldName, valueToIndex); 082 } 083 } 084 085 // Index sort field 086 Object sortValue = getSortValue(ametysObject); 087 String solrSortFieldName = getSolrSortFieldName(); 088 if (isSortable() && sortValue != null && solrSortFieldName != null && !solrFieldName.equals(solrSortFieldName)) 089 { 090 document.setField(solrSortFieldName, sortValue); 091 } 092 } 093 094 /** 095 * Get the sort value represented by this field in the given result ametys object. 096 * @param ametysObject the result ametys object. 097 * @return the content sort value, must be scalar (String, long, double, Date). 098 */ 099 protected Object getSortValue(X ametysObject) 100 { 101 Object value = getValue(ametysObject); 102 if (value == null) 103 { 104 return null; 105 } 106 107 IndexableElementType<T> type = getType(); 108 if (type.getManagedClassArray().isInstance(value)) 109 { 110 T[] values = type.getManagedClassArray().cast(value); 111 return values.length > 0 ? values[0] : value; 112 } 113 else 114 { 115 return value; 116 } 117 } 118 119 public Collection<SchemaDefinition> getSchemaDefinitions() 120 { 121 List<SchemaDefinition> definitions = new ArrayList<>(); 122 123 String solrFieldName = getSolrFieldName(); 124 String sortFieldName = getSolrSortFieldName(); 125 String facetFieldName = getSolrFacetFieldName(); 126 127 boolean multiple = isMultiple(); 128 String type = getType().getSchemaType(); 129 if (solrFieldName != null && type != null) 130 { 131 definitions.add(new FieldDefinition(solrFieldName, type, multiple, false)); 132 133 if (sortFieldName != null && !sortFieldName.equals(solrFieldName)) 134 { 135 definitions.add(new FieldDefinition(sortFieldName, type, false, false)); 136 } 137 138 if (facetFieldName != null && !facetFieldName.equals(solrFieldName)) 139 { 140 // By default the index value in field name will be automatically copy in facet field 141 // So we do not need the index facet field manually 142 definitions.add(new FieldDefinition(facetFieldName, type, multiple, true)); 143 definitions.add(new CopyFieldDefinition(solrFieldName, facetFieldName)); 144 } 145 } 146 147 return definitions; 148 } 149 150 /** 151 * Get the value as a array of String 152 * @param value The value as an object to parse 153 * @return The values as a String array 154 */ 155 protected String[] parseStringArray(Object value) 156 { 157 return value instanceof String 158 ? new String[] {(String) value} 159 : (String[]) value; 160 } 161}