001/* 002 * Copyright 2023 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.model; 017 018import java.util.List; 019import java.util.Locale; 020import java.util.Map; 021import java.util.Set; 022 023import org.apache.avalon.framework.component.Component; 024import org.apache.avalon.framework.configuration.Configuration; 025import org.apache.avalon.framework.configuration.ConfigurationException; 026import org.apache.avalon.framework.configuration.DefaultConfiguration; 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.avalon.framework.service.Serviceable; 030import org.apache.commons.lang3.StringUtils; 031import org.bouncycastle.util.Arrays; 032 033import org.ametys.cms.contenttype.ContentType; 034import org.ametys.cms.data.type.ModelItemTypeExtensionPoint; 035import org.ametys.cms.data.type.indexing.IndexableElementType; 036import org.ametys.cms.model.CMSDataContext; 037import org.ametys.plugins.core.ui.util.ConfigurationHelper; 038import org.ametys.runtime.i18n.I18nizableText; 039import org.ametys.runtime.model.ElementDefinition; 040import org.ametys.runtime.model.ItemParserHelper; 041import org.ametys.runtime.model.exception.UnknownTypeException; 042import org.ametys.runtime.model.type.DataContext; 043import org.ametys.runtime.plugin.component.AbstractLogEnabled; 044 045/** 046 * Helper for {@link CriterionDefinition} 047 */ 048public class CriterionDefinitionHelper extends AbstractLogEnabled implements Component, Serviceable 049{ 050 /** The component role. */ 051 public static final String ROLE = CriterionDefinitionHelper.class.getName(); 052 053 /** The extension point containing all available criterion types */ 054 protected ModelItemTypeExtensionPoint _criterionTypeExtensionPoint; 055 056 public void service(ServiceManager manager) throws ServiceException 057 { 058 _criterionTypeExtensionPoint = (ModelItemTypeExtensionPoint) manager.lookup(ModelItemTypeExtensionPoint.ROLE_CRITERION_DEFINITION); 059 } 060 061 /** 062 * Retrieves the type implementation of the given criterion type identifier 063 * @param <T> the type of the criterion type 064 * @param criterionTypeId the criterion type identifier 065 * @return the criterion type implementation 066 */ 067 @SuppressWarnings("unchecked") 068 public <T> IndexableElementType<T> getCriterionDefinitionType(String criterionTypeId) 069 { 070 if (_criterionTypeExtensionPoint.hasExtension(criterionTypeId)) 071 { 072 return (IndexableElementType<T>) _criterionTypeExtensionPoint.getExtension(criterionTypeId); 073 } 074 else 075 { 076 throw new UnknownTypeException("Unable to retrieve type with identifier '" + criterionTypeId + "'. This type is not available for criteria"); 077 } 078 } 079 080 /** 081 * Retrieves the default widget for the given criterion definition 082 * @param criterionDefinition the criterion definition 083 * @return the default widget for the given criterion definition 084 */ 085 public String getCriterionDefinitionDefaultWidget(CriterionDefinition criterionDefinition) 086 { 087 String defaultWidget = criterionDefinition.getType().getDefaultCriterionWidget(CMSDataContext.newInstance() 088 .withModelItem(criterionDefinition)); 089 090 return "edition.textarea".equals(defaultWidget) ? null : defaultWidget; 091 } 092 093 /** 094 * Retrieves the default widget parameters for the given criterion definition 095 * @param criterionDefinition the criterion definition 096 * @return the default widget parameters for the given criterion definition 097 */ 098 public Map<String, I18nizableText> getCriterionDefinitionDefaultWidgetParameters(CriterionDefinition criterionDefinition) 099 { 100 return criterionDefinition.getType().getDefaultCriterionWidgetParameters(CMSDataContext.newInstance() 101 .withModelItem(criterionDefinition)); 102 } 103 104 /** 105 * Wrap the given configuration to add content types 106 * @param originalConf the configuration to wrap 107 * @param contentTypes the content types to add in wrapped configuration 108 * @return the wrapped configuration 109 * @throws ConfigurationException if an error occurs 110 */ 111 public Configuration wrapCriterionConfiguration(Configuration originalConf, Set<ContentType> contentTypes) throws ConfigurationException 112 { 113 DefaultConfiguration conf = new DefaultConfiguration(originalConf); 114 115 conf.removeChild(conf.getChild("contentTypes")); 116 117 DefaultConfiguration contentTypesConf = new DefaultConfiguration("contentTypes"); 118 for (ContentType contentType : contentTypes) 119 { 120 DefaultConfiguration contentTypeConf = new DefaultConfiguration("type"); 121 contentTypeConf.setAttribute("id", contentType.getId()); 122 contentTypesConf.addChild(contentTypeConf); 123 } 124 125 conf.addChild(contentTypesConf); 126 return conf; 127 } 128 129 /** 130 * Get the label of a facet value for the given criterion. 131 * @param <T> the type of the facet criterion 132 * @param criterion the criterion 133 * @param value the facet value. 134 * @param currentLocale the current locale 135 * @return the label, or null if the value does not exist. 136 */ 137 public <T> I18nizableText getFacetLabel(CriterionDefinition<T> criterion, String value, Locale currentLocale) 138 { 139 DataContext context = DataContext.newInstance() 140 .withModelItem(criterion) 141 .withLocale(currentLocale); 142 IndexableElementType<T> type = criterion.getType(); 143 return type.getFacetLabel(value, context); 144 } 145 146 /** 147 * Check if the given query value is empty 148 * @param value the query value to check 149 * @return <code>true</code> if the given query value is empty, <code>false</code> otherwise 150 */ 151 public boolean isQueryValueEmpty(Object value) 152 { 153 return value == null 154 || value instanceof String strValue && StringUtils.isEmpty(strValue) 155 || value instanceof List listValue && listValue.isEmpty() 156 || value.getClass().isArray() && Arrays.isNullOrEmpty((Object[]) value); 157 } 158 159 /** 160 * Parses the criterion definition default value. 161 * @param defaultValueConfig the default value configuration. 162 * @param definition the element definition. 163 * @param defaultValueType the type of the default value 164 * @return the default value or <code>null</code> if none default value is defined. 165 * @throws ConfigurationException if the configuration is not valid. 166 */ 167 public Object parseCriterionDefinitionDefaultValue(Configuration defaultValueConfig, ElementDefinition definition, String defaultValueType) throws ConfigurationException 168 { 169 return defaultValueType == null 170 ? ConfigurationHelper.parseObject(defaultValueConfig, StringUtils.EMPTY) 171 : ItemParserHelper.parseDefaultValue(defaultValueConfig, definition, defaultValueType); 172 } 173}