001/* 002 * Copyright 2018 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.content.referencetable.search; 017 018import java.util.ArrayList; 019import java.util.Collections; 020import java.util.List; 021import java.util.Map; 022import java.util.Set; 023 024import org.apache.avalon.framework.component.ComponentException; 025import org.apache.avalon.framework.configuration.Configuration; 026import org.apache.avalon.framework.configuration.ConfigurationException; 027import org.apache.avalon.framework.configuration.DefaultConfiguration; 028import org.apache.avalon.framework.service.ServiceException; 029import org.apache.avalon.framework.service.ServiceManager; 030 031import org.ametys.cms.contenttype.ContentTypesHelper; 032import org.ametys.cms.contenttype.MetadataDefinition; 033import org.ametys.cms.repository.Content; 034import org.ametys.cms.search.query.Query.Operator; 035import org.ametys.cms.search.ui.model.AbstractSearchUIModel; 036import org.ametys.cms.search.ui.model.SearchUIColumn; 037import org.ametys.cms.search.ui.model.SearchUICriterion; 038import org.ametys.cms.search.ui.model.SearchUIModel; 039import org.ametys.cms.search.ui.model.impl.IndexingFieldSearchUICriterion; 040import org.ametys.cms.search.ui.model.impl.MetadataSearchUIColumn; 041import org.ametys.cms.search.ui.model.impl.SystemSearchUIColumn; 042import org.ametys.cms.search.ui.model.impl.SystemSearchUICriterion; 043import org.ametys.plugins.repository.AmetysObjectResolver; 044import org.ametys.runtime.plugin.component.ThreadSafeComponentManager; 045 046/** 047 * Implementation of {@link SearchUIModel} for contents referencing the same content's values for a given metadata. 048 */ 049public class ReferencingContentsWithSameValuesSearchUIModel extends AbstractSearchUIModel 050{ 051 /** The content type helper. */ 052 protected ContentTypesHelper _cTypeHelper; 053 054 /** ComponentManager for {@link SearchUICriterion}s. */ 055 protected ThreadSafeComponentManager<SearchUICriterion> _searchCriterionManager; 056 057 /** ComponentManager for {@link SearchUIColumn}s. */ 058 protected ThreadSafeComponentManager<SearchUIColumn> _searchColumnManager; 059 /** The search column roles. */ 060 protected List<String> _searchColumnRoles; 061 062 private AmetysObjectResolver _resolver; 063 064 @Override 065 public void service(ServiceManager manager) throws ServiceException 066 { 067 super.service(manager); 068 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 069 _cTypeHelper = (ContentTypesHelper) manager.lookup(ContentTypesHelper.ROLE); 070 } 071 072 @Override 073 public Set<String> getContentTypes(Map<String, Object> contextualParameters) 074 { 075 if (contextualParameters != null && contextualParameters.containsKey("contentId") && contextualParameters.containsKey("referenceField")) 076 { 077 // Get the content type which has declared the metadata 078 String contentId = (String) contextualParameters.get("contentId"); 079 Content content = _resolver.resolveById(contentId); 080 081 String referenceMetadataPath = (String) contextualParameters.get("referenceField"); 082 MetadataDefinition metadataDef = _cTypeHelper.getMetadataDefinition(referenceMetadataPath, content); 083 if (metadataDef != null) 084 { 085 return Collections.singleton(metadataDef.getReferenceContentType()); 086 } 087 } 088 089 return Collections.emptySet(); 090 } 091 092 @Override 093 public Set<String> getExcludedContentTypes(Map<String, Object> contextualParameters) 094 { 095 return Collections.emptySet(); 096 } 097 098 @Override 099 public Map<String, SearchUICriterion> getCriteria(Map<String, Object> contextualParameters) 100 { 101 List<SearchUICriterion> criteria = new ArrayList<>(); 102 103 if (contextualParameters.containsKey("contentId")) 104 { 105 try 106 { 107 _searchCriterionManager = new ThreadSafeComponentManager<>(); 108 _searchCriterionManager.setLogger(getLogger()); 109 _searchCriterionManager.contextualize(_context); 110 _searchCriterionManager.service(_manager); 111 112 List<String> roles = new ArrayList<>(); 113 114 String contentId = (String) contextualParameters.get("contentId"); 115 116 Content content = _resolver.resolveById(contentId); 117 118 String firstCTypeId = content.getTypes()[0]; 119 120 Configuration conf = getIndexingFieldCriteriaConfiguration(firstCTypeId, "title", Operator.SEARCH); 121 _searchCriterionManager.addComponent("cms", null, "title", IndexingFieldSearchUICriterion.class, conf); 122 roles.add("title"); 123 124 conf = getSystemCriteriaConfiguration(firstCTypeId, "fulltext"); 125 _searchCriterionManager.addComponent("cms", null, "fulltext", SystemSearchUICriterion.class, conf); 126 roles.add("fulltext"); 127 128 conf = getSystemCriteriaConfiguration(firstCTypeId, "workflowStep"); 129 _searchCriterionManager.addComponent("cms", null, "workflowStep", SystemSearchUICriterion.class, conf); 130 roles.add("workflowStep"); 131 132 if (contextualParameters.containsKey("referenceField") && contextualParameters.containsKey("referenceValues")) 133 { 134 String referenceMetadataPath = ((String) contextualParameters.get("referenceField")).replaceAll("\\.", "/"); 135 MetadataDefinition metadataDef = _cTypeHelper.getMetadataDefinition(referenceMetadataPath, content); 136 137 if (metadataDef != null) 138 { 139 @SuppressWarnings("unchecked") 140 List<String> referenceMetadataValues = (List<String>) contextualParameters.get("referenceValues"); 141 142 DefaultConfiguration referenceFieldConf = new DefaultConfiguration("criteria"); 143 // Default value(s) 144 for (String referenceMetadataValue : referenceMetadataValues) 145 { 146 DefaultConfiguration defaultValueConf = new DefaultConfiguration("default-value"); 147 defaultValueConf.setValue(referenceMetadataValue); 148 referenceFieldConf.addChild(defaultValueConf); 149 } 150 // AND query on multiple entries 151 DefaultConfiguration multipleOperandConf = new DefaultConfiguration("multiple-operand"); 152 multipleOperandConf.setValue("and"); 153 referenceFieldConf.addChild(multipleOperandConf); 154 // Hidden 155 referenceFieldConf.setAttribute("hidden", "true"); 156 157 conf = getIndexingFieldCriteriaConfiguration(referenceFieldConf, metadataDef.getReferenceContentType(), referenceMetadataPath, null, null); 158 _searchCriterionManager.addComponent("cms", null, "referenceField", IndexingFieldSearchUICriterion.class, conf); 159 roles.add("referenceField"); 160 } 161 } 162 163 _searchCriterionManager.initialize(); 164 165 // Lookup. 166 for (String role : roles) 167 { 168 criteria.add(_searchCriterionManager.lookup(role)); 169 } 170 171 setCriteria(criteria); 172 173 // Dispose 174 _searchCriterionManager.dispose(); 175 _searchCriterionManager = null; 176 } 177 catch (Exception e) 178 { 179 getLogger().error("Error getting the search criteria.", e); 180 throw new IllegalStateException("Error getting the search criteria.", e); 181 } 182 } 183 else 184 { 185 setCriteria(criteria); 186 } 187 188 return super.getCriteria(contextualParameters); 189 } 190 191 @Override 192 public Map<String, SearchUICriterion> getAdvancedCriteria(Map<String, Object> contextualParameters) 193 { 194 return Collections.emptyMap(); 195 } 196 197 @Override 198 public Map<String, SearchUICriterion> getFacetedCriteria(Map<String, Object> contextualParameters) 199 { 200 return Collections.emptyMap(); 201 } 202 203 @Override 204 public Map<String, SearchUIColumn> getResultFields(Map<String, Object> contextualParameters) 205 { 206 List<SearchUIColumn> columns = new ArrayList<>(); 207 208 try 209 { 210 _searchColumnManager = new ThreadSafeComponentManager<>(); 211 _searchColumnManager.setLogger(getLogger()); 212 _searchColumnManager.contextualize(_context); 213 _searchColumnManager.service(_manager); 214 215 _searchColumnRoles = new ArrayList<>(); 216 217 if (contextualParameters.containsKey("contentId")) 218 { 219 String contentId = (String) contextualParameters.get("contentId"); 220 221 Content content = _resolver.resolveById(contentId); 222 223 String firstCTypeId = content.getTypes()[0]; 224 225 // Column title 226 Configuration conf = getMetadataColumnConfiguration(firstCTypeId, "title"); 227 _searchColumnManager.addComponent("cms", null, "title", MetadataSearchUIColumn.class, conf); 228 _searchColumnRoles.add("title"); 229 230 if (contextualParameters.containsKey("referenceField")) 231 { 232 String referenceMetadataPath = ((String) contextualParameters.get("referenceField")).replaceAll("\\.", "/"); 233 MetadataDefinition metadataDef = _cTypeHelper.getMetadataDefinition(referenceMetadataPath, content); 234 if (metadataDef != null) 235 { 236 conf = getMetadataColumnConfiguration(metadataDef.getReferenceContentType(), referenceMetadataPath); 237 _searchColumnManager.addComponent("cms", null, "referenceField", MetadataSearchUIColumn.class, conf); 238 _searchColumnRoles.add("referenceField"); 239 } 240 } 241 } 242 243 addSystemColumnComponent("contributor"); 244 addSystemColumnComponent("lastModified"); 245 addSystemColumnComponent("contentTypes"); 246 addSystemColumnComponent("contentLanguage"); 247 addSystemColumnComponent("workflowStep"); 248 249 _searchColumnManager.initialize(); 250 251 for (String role : _searchColumnRoles) 252 { 253 columns.add(_searchColumnManager.lookup(role)); 254 } 255 256 _searchColumnManager.dispose(); 257 _searchColumnManager = null; 258 } 259 catch (Exception e) 260 { 261 getLogger().error("Error getting the result fields.", e); 262 throw new IllegalStateException("Error getting the result fields.", e); 263 } 264 265 setResultFields(columns); 266 267 return super.getResultFields(contextualParameters); 268 } 269 270 /** 271 * Add a system column component to the manager. 272 * @param property the system property. 273 * @throws ConfigurationException if a configuration error occurs. 274 * @throws ComponentException if a component cannot be initialized. 275 */ 276 protected void addSystemColumnComponent(String property) throws ConfigurationException, ComponentException 277 { 278 Configuration conf = getSystemColumnConfiguration(null, property); 279 _searchColumnManager.addComponent("cms", null, property, SystemSearchUIColumn.class, conf); 280 _searchColumnRoles.add(property); 281 } 282 283}