001/* 002 * Copyright 2016 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.solr; 017 018import java.util.Collection; 019import java.util.HashMap; 020import java.util.Map; 021import java.util.Set; 022 023import org.apache.avalon.framework.component.Component; 024import org.apache.avalon.framework.logger.AbstractLogEnabled; 025import org.apache.avalon.framework.service.ServiceException; 026import org.apache.avalon.framework.service.ServiceManager; 027import org.apache.avalon.framework.service.Serviceable; 028 029import org.ametys.cms.content.indexing.solr.SolrFieldHelper; 030import org.ametys.cms.contenttype.ContentType; 031import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 032import org.ametys.cms.contenttype.ContentTypesHelper; 033import org.ametys.cms.contenttype.MetadataDefinition; 034import org.ametys.cms.contenttype.MetadataType; 035import org.ametys.cms.contenttype.RepeaterDefinition; 036import org.ametys.cms.contenttype.indexing.IndexingField; 037import org.ametys.cms.contenttype.indexing.IndexingModel; 038import org.ametys.cms.contenttype.indexing.MetadataIndexingField; 039import org.ametys.cms.search.SearchField; 040import org.ametys.cms.search.model.SystemProperty; 041import org.ametys.cms.search.model.SystemPropertyExtensionPoint; 042import org.ametys.core.ui.Callable; 043 044/** 045 * Helper for solr query editor. 046 */ 047public class SolrQueryHelper extends AbstractLogEnabled implements Component, Serviceable 048{ 049 050 /** The component role. */ 051 public static final String ROLE = SolrQueryHelper.class.getName(); 052 053 /** The content type extension point. */ 054 protected ContentTypeExtensionPoint _cTypeEP; 055 056 /** The content types helper. */ 057 protected ContentTypesHelper _contentTypesHelper; 058 059 /** The extension point for system properties */ 060 protected SystemPropertyExtensionPoint _systemPropertyEP; 061 062 @Override 063 public void service(ServiceManager serviceManager) throws ServiceException 064 { 065 _cTypeEP = (ContentTypeExtensionPoint) serviceManager.lookup(ContentTypeExtensionPoint.ROLE); 066 _contentTypesHelper = (ContentTypesHelper) serviceManager.lookup(ContentTypesHelper.ROLE); 067 _systemPropertyEP = (SystemPropertyExtensionPoint) serviceManager.lookup(SystemPropertyExtensionPoint.ROLE); 068 } 069 070 /** 071 * Get all the content types and their indexing fields. 072 * @param language the query language (because string field names are language-dependent). 073 * @return the content types and their metadatas. 074 */ 075 @Callable 076 public Map<String, Object> getAllContentTypeIndexingFields(String language) 077 { 078 Map<String, Object> results = new HashMap<>(); 079 Map<String, Object> contentTypes = new HashMap<>(); 080 results.put("contentTypes", contentTypes); 081 082 for (String cTypeId : _cTypeEP.getExtensionsIds()) 083 { 084 ContentType contentType = _cTypeEP.getExtension(cTypeId); 085 086 _putContentType(contentTypes, contentType, language); 087 } 088 089 return results; 090 } 091 092 private void _putContentType(Map<String, Object> contentTypes, ContentType contentType, String language) 093 { 094 String cTypeId = contentType.getId(); 095 096 Map<String, Object> properties = new HashMap<>(); 097 contentTypes.put(cTypeId, properties); 098 099 properties.put("type", "contentType"); 100 properties.put("superTypes", contentType.getSupertypeIds()); 101 102 Map<String, Object> fields = new HashMap<>(); 103 properties.put("fields", fields); 104 105 IndexingModel indexingModel = contentType.getIndexingModel(); 106 for (IndexingField field : indexingModel.getFields()) 107 { 108 if (field instanceof MetadataIndexingField) 109 { 110 MetadataIndexingField metaField = (MetadataIndexingField) field; 111 MetadataDefinition metaDef = metaField.getMetadataDefinition(); 112 113 if (metaDef != null) 114 { 115 _putMetadataIndexingField(fields, field.getName(), metaDef, cTypeId, language); 116 } 117 } 118 else 119 { 120 _putIndexingField(fields, field, language); 121 } 122 } 123 } 124 125 private void _putIndexingField(Map<String, Object> metadata, IndexingField field, String language) 126 { 127 String name = field.getName(); 128 MetadataType type = field.getType(); 129 130 Map<String, Object> properties = new HashMap<>(); 131 metadata.put(name, properties); 132 133 properties.put("type", type.name().toLowerCase()); 134 properties.put("fl", SolrFieldHelper.getIndexingFieldName(type, name)); 135 136 if (type == MetadataType.STRING) 137 { 138 properties.put("ftFl", name + SolrFieldHelper.getFulltextFieldSuffix(language)); 139 properties.put("wcFl", name + SolrFieldHelper.getWildcardFieldSuffix()); 140 } 141 } 142 143 private void _putMetadataIndexingField(Map<String, Object> fields, String name, MetadataDefinition metaDef, String cTypeId, String language) 144 { 145 if (metaDef.getReferenceContentType().equals(cTypeId)) 146 { 147 MetadataType type = metaDef.getType(); 148 149 Map<String, Object> properties = new HashMap<>(); 150 151 switch (type) 152 { 153 case STRING: 154 case LONG: 155 case DOUBLE: 156 case DATE: 157 case DATETIME: 158 case BOOLEAN: 159 case CONTENT: 160 case SUB_CONTENT: 161 case USER: 162 case GEOCODE: 163 fields.put(name, properties); 164 _putSimpleMetadata(properties, metaDef, language); 165 break; 166 case COMPOSITE: 167 fields.put(name, properties); 168 _putCompositeMetadata(properties, metaDef, cTypeId, language); 169 break; 170 default: 171 break; 172 } 173 } 174 } 175 176 private void _putCompositeMetadata(Map<String, Object> properties, MetadataDefinition metaDef, String cTypeId, String language) 177 { 178 String name = metaDef.getName(); 179 180 // type 181 properties.put("type", metaDef instanceof RepeaterDefinition ? "repeater" : "composite"); 182 183 // solr field 184// String fl = (metaDef instanceof RepeaterDefinition) ? SolrFieldHelper.getJoinFieldName(name) : name; 185 properties.put("fl", name); 186 187 if (metaDef instanceof RepeaterDefinition) 188 { 189 properties.put("joinFl", SolrFieldHelper.getJoinFieldName(name)); 190 } 191 192 Map<String, Object> subFields = new HashMap<>(); 193 properties.put("fields", subFields); 194 195 for (String subMetaName : metaDef.getMetadataNames()) 196 { 197 MetadataDefinition subMetaDef = metaDef.getMetadataDefinition(subMetaName); 198 _putMetadataIndexingField(subFields, subMetaName, subMetaDef, cTypeId, language); 199 } 200 } 201 202 private void _putSimpleMetadata(Map<String, Object> properties, MetadataDefinition metaDef, String language) 203 { 204 String name = metaDef.getName(); 205 MetadataType type = metaDef.getType(); 206 207 properties.put("type", type.name().toLowerCase()); 208 // solr field 209// properties.put("fl", SolrFieldHelper.getIndexingFieldName(type, path)); 210 properties.put("fl", SolrFieldHelper.getIndexingFieldName(type, name, language)); 211 212 if (type == MetadataType.STRING && metaDef.getEnumerator() == null) 213 { 214// properties.put("ftFl", name + SolrFieldHelper.getStringFieldSuffix(language, true)); 215 properties.put("ftFl", name + SolrFieldHelper.getFulltextFieldSuffix(language)); 216 properties.put("wcFl", name + SolrFieldHelper.getWildcardFieldSuffix()); 217 } 218 else if (type == MetadataType.CONTENT || type == MetadataType.SUB_CONTENT) 219 { 220 properties.put("cType", metaDef.getContentType()); 221 properties.put("joinFl", SolrFieldHelper.getJoinFieldName(name)); 222 } 223 } 224 225 /** 226 * Get content types' common ancestor. 227 * @param contentTypes The content types. 228 * @return a Map with the common ancestor if found, an empty Map if not found. 229 */ 230 @Callable 231 public Map<String, Object> getCommonAncestor(Collection<String> contentTypes) 232 { 233 Map<String, Object> results = new HashMap<>(); 234 235 String commonAncestor = _contentTypesHelper.getCommonAncestor(contentTypes); 236 if (commonAncestor != null) 237 { 238 results.put("commonAncestor", commonAncestor); 239 } 240 241 return results; 242 } 243 244 /** 245 * Get the common fields. 246 * @param language the query language (because string field names are language-dependent). 247 * @return the common fields. 248 */ 249 @Callable 250 public Map<String, Object> getCommonFields(String language) 251 { 252 Map<String, Object> results = new HashMap<>(); 253 254 Map<String, Object> systemProps = new HashMap<>(); 255 results.put("fields", systemProps); 256 257 _putTitleMetadata(systemProps, language); 258 259 Set<String> extensionsIds = _systemPropertyEP.getExtensionsIds(); 260 for (String extensionId : extensionsIds) 261 { 262 SystemProperty property = _systemPropertyEP.getExtension(extensionId); 263 SearchField searchField = property.getSearchField(); 264 if (searchField != null) 265 { 266 Map<String, Object> properties = new HashMap<>(); 267 systemProps.put(extensionId, properties); 268 269 // type 270 properties.put("type", property.getType().name().toLowerCase()); 271 272 // solr field 273 properties.put("fl", searchField.getName()); 274 } 275 } 276 277 return results; 278 } 279 280 private void _putTitleMetadata(Map<String, Object> systemProps, String language) 281 { 282 for (String cTypeId : _cTypeEP.getExtensionsIds()) 283 { 284 ContentType cType = _cTypeEP.getExtension(cTypeId); 285 if (cType.hasMetadataDefinition("title")) 286 { 287 MetadataDefinition titleDef = cType.getMetadataDefinition("title"); 288 289 Map<String, Object> properties = new HashMap<>(); 290 systemProps.put("title", properties); 291 292 _putSimpleMetadata(properties, titleDef, language); 293 break; 294 } 295 } 296 } 297 298}