001/* 002 * Copyright 2015 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.LinkedHashMap; 019import java.util.Map; 020import java.util.Optional; 021 022import org.apache.avalon.framework.configuration.Configuration; 023import org.apache.avalon.framework.configuration.ConfigurationException; 024import org.apache.avalon.framework.service.ServiceException; 025import org.apache.avalon.framework.service.ServiceManager; 026import org.apache.cocoon.xml.AttributesImpl; 027import org.apache.cocoon.xml.XMLUtils; 028import org.xml.sax.ContentHandler; 029import org.xml.sax.SAXException; 030 031import org.ametys.cms.data.type.indexing.IndexableElementType; 032import org.ametys.cms.languages.Language; 033import org.ametys.cms.languages.LanguageEnumerator; 034import org.ametys.cms.languages.LanguagesManager; 035import org.ametys.cms.model.CMSDataContext; 036import org.ametys.cms.repository.Content; 037import org.ametys.cms.search.model.CriterionDefinitionAwareElementDefinition; 038import org.ametys.cms.search.model.CriterionDefinitionHelper; 039import org.ametys.cms.search.model.SystemProperty; 040import org.ametys.cms.search.query.ContentLanguageQuery; 041import org.ametys.cms.search.query.Query; 042import org.ametys.cms.search.query.Query.Operator; 043import org.ametys.core.model.type.ModelItemTypeHelper; 044import org.ametys.core.util.I18nUtils; 045import org.ametys.runtime.model.Enumerator; 046import org.ametys.runtime.model.type.DataContext; 047import org.ametys.runtime.model.type.ModelItemTypeConstants; 048import org.ametys.runtime.plugin.component.ThreadSafeComponentManager; 049 050/** 051 * {@link SystemProperty} which represents the language of a Content. 052 */ 053public class LanguageSystemProperty extends AbstractSystemProperty<String, Content> implements CriterionDefinitionAwareElementDefinition<String>, IndexationAwareSystemProperty<String, Content> 054{ 055 /** Solr field name. */ 056 public static final String SOLR_FIELD_NAME = "contentLanguage"; 057 058 /** The language manager. */ 059 protected LanguagesManager _languageManager; 060 061 /** The i18n utils. */ 062 protected I18nUtils _i18nUtils; 063 064 /** The criterion definition helper */ 065 protected CriterionDefinitionHelper _criterionDefinitionHelper; 066 067 @Override 068 public void service(ServiceManager manager) throws ServiceException 069 { 070 super.service(manager); 071 _languageManager = (LanguagesManager) manager.lookup(LanguagesManager.ROLE); 072 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 073 _criterionDefinitionHelper = (CriterionDefinitionHelper) manager.lookup(CriterionDefinitionHelper.ROLE); 074 } 075 076 @Override 077 public Query getQuery(Object value, Operator operator, String language, Map<String, Object> contextualParameters) 078 { 079 if (_criterionDefinitionHelper.isQueryValueEmpty(value)) 080 { 081 return new ContentLanguageQuery(); 082 } 083 else if (value instanceof String[] values) 084 { 085 return new ContentLanguageQuery(operator, values); 086 } 087 else 088 { 089 String langValue = "CURRENT".equals(value) ? language : (String) value; 090 return new ContentLanguageQuery(operator, langValue); 091 } 092 } 093 094 @Override 095 public String getRenderer() 096 { 097 return "Ametys.plugins.cms.search.SearchGridHelper.renderLanguage"; 098 } 099 100 @Override 101 public String getConverter() 102 { 103 return "Ametys.plugins.cms.search.SearchGridHelper.convertLanguage"; 104 } 105 106 @Override 107 public Integer getColumnWidth() 108 { 109 return 70; 110 } 111 112 public String getSolrFieldName() 113 { 114 return SOLR_FIELD_NAME; 115 } 116 117 public String getSolrSortFieldName() 118 { 119 return SOLR_FIELD_NAME + "_sort"; 120 } 121 122 public String getSolrFacetFieldName() 123 { 124 return SOLR_FIELD_NAME + "_dv"; 125 } 126 127 @Override 128 public Object getValue(Content content) 129 { 130 return content.getLanguage(); 131 } 132 133 public Object valueToJSON(Content content, DataContext context) 134 { 135 String languageCode = (String) getValue(content); 136 Map<String, Object> infos = new LinkedHashMap<>(); 137 138 infos.put("code", languageCode); 139 140 if (languageCode != null) 141 { 142 Language language = _languageManager.getLanguage(languageCode); 143 if (language != null) 144 { 145 infos.put("icon", language.getSmallIcon()); 146 infos.put("label", language.getLabel()); 147 } 148 } 149 150 return infos; 151 } 152 153 public void valueToSAX(ContentHandler contentHandler, Content content, DataContext context) throws SAXException 154 { 155 Language language = Optional.of(content) 156 .map(this::getValue) 157 .map(String.class::cast) 158 .map(_languageManager::getLanguage) 159 .orElse(null); 160 161 if (language != null) 162 { 163 AttributesImpl attr = ModelItemTypeHelper.getXMLAttributesFromDataContext(context); 164 attr.addCDATAAttribute("code", language.getCode()); 165 XMLUtils.startElement(contentHandler, getName(), attr); 166 language.getLabel().toSAX(contentHandler); 167 XMLUtils.endElement(contentHandler, getName()); 168 } 169 } 170 171 @Override 172 public Object getSortValue(Content content) 173 { 174 Language language = Optional.of(content) 175 .map(this::getValue) 176 .map(String.class::cast) 177 .map(_languageManager::getLanguage) 178 .orElse(null); 179 180 if (language != null) 181 { 182 return _i18nUtils.translate(language.getLabel(), language.getCode()); 183 } 184 185 return null; 186 } 187 188 @Override 189 public Enumerator<String> getDefaultCriterionEnumerator(Configuration configuration, ThreadSafeComponentManager<Enumerator> enumeratorManager) throws ConfigurationException 190 { 191 String role = "enumerator"; 192 enumeratorManager.addComponent(getPluginName(), null, role, LanguageEnumerator.class, configuration); 193 194 try 195 { 196 enumeratorManager.initialize(); 197 return enumeratorManager.lookup(role); 198 } 199 catch (Exception e) 200 { 201 throw new ConfigurationException("Unable to initialize the language enumerator for system property '" + getName() + "'.", configuration, e); 202 } 203 } 204 205 @Override 206 protected String getTypeId() 207 { 208 return ModelItemTypeConstants.STRING_TYPE_ID; 209 } 210 211 public IndexableElementType getDefaultCriterionType() 212 { 213 CMSDataContext context = CMSDataContext.newInstance() 214 .withModelItem(this); 215 216 String typeId = getType().getDefaultCriterionTypeId(context); 217 return _criterionDefinitionHelper.getCriterionDefinitionType(typeId); 218 } 219}