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.ui.model; 017 018import java.util.Collection; 019import java.util.Collections; 020import java.util.HashSet; 021import java.util.LinkedHashMap; 022import java.util.Map; 023import java.util.Set; 024 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.context.Context; 029import org.apache.avalon.framework.context.ContextException; 030import org.apache.avalon.framework.context.Contextualizable; 031import org.apache.avalon.framework.service.ServiceException; 032import org.apache.avalon.framework.service.ServiceManager; 033import org.apache.avalon.framework.service.Serviceable; 034import org.slf4j.Logger; 035 036import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 037import org.ametys.cms.search.model.SearchCriterion; 038import org.ametys.cms.search.query.Query.Operator; 039import org.ametys.runtime.i18n.I18nizableText; 040import org.ametys.runtime.plugin.component.LogEnabled; 041 042/** 043 * Abstract class for SearchUIModel. 044 */ 045public abstract class AbstractSearchUIModel implements SearchUIModel, LogEnabled, Serviceable, Contextualizable 046{ 047 /** The content type extension point */ 048 protected ContentTypeExtensionPoint _cTypeEP; 049 /** The search model helper. */ 050 protected SearchUIModelHelper _searchModelHelper; 051 /** The logger. */ 052 protected Logger _logger; 053 /** The service manager */ 054 protected ServiceManager _manager; 055 /** The context. */ 056 protected Context _context; 057 058 /** The content types of this search model. */ 059 protected Set<String> _cTypes; 060 /** The content types excluded from this search model. */ 061 protected Set<String> _excludedCTypes; 062 063 /** The search criteria in simple mode, indexed by ID. */ 064 protected Map<String, SearchUICriterion> _searchCriteria; 065 /** The search criteria in advanced mode, indexed by ID. */ 066 protected Map<String, SearchUICriterion> _advancedSearchCriteria; 067 /** The search criteria used as facets, indexed by ID. */ 068 protected Map<String, SearchUICriterion> _facetedCriteria; 069 /** The result columns, indexed by ID. */ 070 protected Map<String, SearchUIColumn> _columns; 071 072 public void setLogger(final Logger logger) 073 { 074 _logger = logger; 075 } 076 077 /** 078 * Get the logger. 079 * @return the logger. 080 */ 081 protected final Logger getLogger() 082 { 083 return _logger; 084 } 085 086 @Override 087 public void contextualize(Context context) throws ContextException 088 { 089 _context = context; 090 } 091 092 @Override 093 public void service(ServiceManager manager) throws ServiceException 094 { 095 _cTypeEP = (ContentTypeExtensionPoint) manager.lookup(ContentTypeExtensionPoint.ROLE); 096 _searchModelHelper = (SearchUIModelHelper) manager.lookup(SearchUIModelHelper.ROLE); 097 _manager = manager; 098 } 099 100 @Override 101 public Set<String> getContentTypes(Map<String, Object> contextualParameters) 102 { 103 return Collections.unmodifiableSet(_cTypes); 104 } 105 106 /** 107 * Set the content types. 108 * @param cTypes The content types. 109 */ 110 public void setContentTypes(Set<String> cTypes) 111 { 112 _cTypes = new HashSet<>(cTypes); 113 } 114 115 @Override 116 public Set<String> getExcludedContentTypes(Map<String, Object> contextualParameters) 117 { 118 return Collections.unmodifiableSet(_excludedCTypes); 119 } 120 121 /** 122 * Set the excluded content types. 123 * @param cTypes The excluded content types. 124 */ 125 public void setExcludedContentTypes(Set<String> cTypes) 126 { 127 _excludedCTypes = new HashSet<>(cTypes); 128 } 129 130 @Override 131 public Map<String, SearchUICriterion> getCriteria(Map<String, Object> contextualParameters) 132 { 133 return Collections.unmodifiableMap(_searchCriteria); 134 } 135 136 /** 137 * Set the criteria in simple mode. 138 * @param criteria A collection of search criteria. 139 */ 140 public void setCriteria(Collection<SearchUICriterion> criteria) 141 { 142 _searchCriteria = new LinkedHashMap<>(); 143 for (SearchCriterion criterion : criteria) 144 { 145 _searchCriteria.put(criterion.getId(), (SearchUICriterion) criterion); 146 } 147 } 148 149 @Override 150 public Map<String, SearchUICriterion> getAdvancedCriteria(Map<String, Object> contextualParameters) 151 { 152 return Collections.unmodifiableMap(_advancedSearchCriteria); 153 } 154 155 /** 156 * Set the criteria in advanced mode. 157 * @param criteria A collection of search criteria. 158 */ 159 public void setAdvancedCriteria(Collection<SearchUICriterion> criteria) 160 { 161 _advancedSearchCriteria = new LinkedHashMap<>(); 162 for (SearchUICriterion criterion : criteria) 163 { 164 _advancedSearchCriteria.put(criterion.getId(), criterion); 165 } 166 } 167 168 @Override 169 public Map<String, SearchUICriterion> getFacetedCriteria(Map<String, Object> contextualParameters) 170 { 171 return Collections.unmodifiableMap(_facetedCriteria); 172 } 173 174 /** 175 * Set the criteria to use as facets. 176 * @param criteria A collection of search criteria. 177 */ 178 public void setFacetedCriteria(Collection<SearchCriterion> criteria) 179 { 180 _facetedCriteria = new LinkedHashMap<>(); 181 for (SearchCriterion criterion : criteria) 182 { 183 _facetedCriteria.put(criterion.getId(), (SearchUICriterion) criterion); 184 } 185 } 186 187 @Override 188 public Map<String, SearchUIColumn> getResultFields(Map<String, Object> contextualParameters) 189 { 190 return Collections.unmodifiableMap(_columns); 191 } 192 193 /** 194 * Set the result columns. 195 * @param fields A collection of search columns. 196 */ 197 public void setResultFields(Collection<SearchUIColumn> fields) 198 { 199 _columns = new LinkedHashMap<>(); 200 for (SearchUIColumn column : fields) 201 { 202 _columns.put(column.getId(), column); 203 } 204 } 205 206 @Override 207 public int getPageSize(Map<String, Object> contextualParameters) 208 { 209 // Use the default value or unlimited. 210 return -1; 211 } 212 213 @Override 214 public String getWorkspace(Map<String, Object> contextualParameters) 215 { 216 // Use the default workspace. 217 return null; 218 } 219 220 @Override 221 public String getSearchUrl(Map<String, Object> contextualParameters) 222 { 223 return "search/list.json"; 224 } 225 226 @Override 227 public String getSearchUrlPlugin(Map<String, Object> contextualParameters) 228 { 229 return "cms"; 230 } 231 232 @Override 233 public String getExportCSVUrl(Map<String, Object> contextualParameters) 234 { 235 return "search/export.csv"; 236 } 237 238 @Override 239 public String getExportCSVUrlPlugin(Map<String, Object> contextualParameters) 240 { 241 return "cms"; 242 } 243 244 @Override 245 public String getExportDOCUrl(Map<String, Object> contextualParameters) 246 { 247 return "search/export.doc"; 248 } 249 250 @Override 251 public String getExportDOCUrlPlugin(Map<String, Object> contextualParameters) 252 { 253 return "cms"; 254 } 255 256 @Override 257 public String getExportXMLUrl(Map<String, Object> contextualParameters) 258 { 259 return "search/export.xml"; 260 } 261 262 @Override 263 public String getExportXMLUrlPlugin(Map<String, Object> contextualParameters) 264 { 265 return "cms"; 266 } 267 268 @Override 269 public String getPrintUrl(Map<String, Object> contextualParameters) 270 { 271 return "search/print.html"; 272 } 273 274 @Override 275 public String getPrintUrlPlugin(Map<String, Object> contextualParameters) 276 { 277 return "cms"; 278 } 279 280 @Override 281 public String getSummaryView() 282 { 283 return null; 284 } 285 286 /** 287 * Get the configuration of a metadata criteria component. 288 * @param contentTypeId the content type ID. 289 * @param path the field path. 290 * @param operator the criteria operator, can be null. 291 * @return the configuration to provide to the metadata criteria component. 292 * @throws ConfigurationException if an error occurs. 293 */ 294 protected Configuration getIndexingFieldCriteriaConfiguration(String contentTypeId, String path, Operator operator) throws ConfigurationException 295 { 296 return getIndexingFieldCriteriaConfiguration(contentTypeId, path, operator, null); 297 } 298 299 /** 300 * Get the configuration of a metadata criteria component. 301 * @param contentTypeId the content type ID. 302 * @param path the field path. 303 * @param operator the criteria operator, can be null. 304 * @param group The group. Can ne null. 305 * @return the configuration to provide to the metadata criteria component. 306 * @throws ConfigurationException if an error occurs. 307 */ 308 protected Configuration getIndexingFieldCriteriaConfiguration(String contentTypeId, String path, Operator operator, I18nizableText group) throws ConfigurationException 309 { 310 return getIndexingFieldCriteriaConfiguration(new DefaultConfiguration("criteria"), contentTypeId, path, operator, group); 311 } 312 313 /** 314 * Get the configuration of a metadata criteria component. 315 * @param originalConf the original criteria configuration. 316 * @param contentTypeId the content type ID. 317 * @param path the field path, separated by '/'. 318 * @param operator the criteria operator, can be null. 319 * @param group The group. Can ne null. 320 * @return the configuration to provide to the metadata criterion component. 321 * @throws ConfigurationException if an error occurs. 322 */ 323 protected Configuration getIndexingFieldCriteriaConfiguration(Configuration originalConf, String contentTypeId, String path, Operator operator, I18nizableText group) throws ConfigurationException 324 { 325 DefaultConfiguration conf = new DefaultConfiguration(originalConf); 326 327 DefaultConfiguration metaConf = new DefaultConfiguration("field"); 328 conf.addChild(metaConf); 329 metaConf.setAttribute("path", path); 330 331 if (operator != null) 332 { 333 DefaultConfiguration opConf = new DefaultConfiguration("test-operator"); 334 conf.addChild(opConf); 335 opConf.setValue(operator.getName()); 336 } 337 338 addContentTypesConfiguration(conf, contentTypeId); 339 340 if (group != null) 341 { 342 DefaultConfiguration groupConf = new DefaultConfiguration("group"); 343 groupConf.setAttribute("i18n", group.isI18n()); 344 groupConf.setValue(group.isI18n() ? group.getCatalogue() + ":" + group.getKey() : group.getLabel()); 345 conf.addChild(groupConf); 346 } 347 348 return conf; 349 } 350 351 /** 352 * Get the configuration of a system criteria component. 353 * @param contentTypeId the content type ID. 354 * @param property the system property. 355 * @return the configuration to provide to the system criterion component. 356 */ 357 protected Configuration getSystemCriteriaConfiguration(String contentTypeId, String property) 358 { 359 return getSystemCriteriaConfiguration(contentTypeId, property, null); 360 } 361 362 /** 363 * Get the configuration of a system criteria component. 364 * @param contentTypeId the content type ID. 365 * @param property the system property. 366 * @param group The group. Can ne null. 367 * @return the configuration to provide to the system criterion component. 368 */ 369 protected Configuration getSystemCriteriaConfiguration(String contentTypeId, String property, I18nizableText group) 370 { 371 try 372 { 373 return getSystemCriteriaConfiguration(new DefaultConfiguration("criteria"), contentTypeId, property, group); 374 } 375 catch (ConfigurationException e) 376 { 377 // Ignore, just can't happen. 378 return null; 379 } 380 } 381 382 /** 383 * Get the configuration of a system criteria component. 384 * @param originalConf the original column configuration. 385 * @param contentTypeId the content type ID. 386 * @param property the system property. 387 * @param group The group. Can ne null. 388 * @return the configuration to provide to the system criterion component. 389 * @throws ConfigurationException if an error occurs. 390 */ 391 protected Configuration getSystemCriteriaConfiguration(Configuration originalConf, String contentTypeId, String property, I18nizableText group) throws ConfigurationException 392 { 393 DefaultConfiguration conf = new DefaultConfiguration(originalConf); 394 395 DefaultConfiguration propConf = new DefaultConfiguration("systemProperty"); 396 propConf.setAttribute("name", property); 397 conf.addChild(propConf); 398 399 addContentTypesConfiguration(conf, contentTypeId); 400 401 if (group != null) 402 { 403 DefaultConfiguration groupConf = new DefaultConfiguration("group"); 404 groupConf.setAttribute("i18n", group.isI18n()); 405 groupConf.setValue(group.isI18n() ? group.getCatalogue() + ":" + group.getKey() : group.getLabel()); 406 conf.addChild(groupConf); 407 } 408 409 return conf; 410 } 411 412 /** 413 * Get the configuration of a custom criteria component. 414 * @param originalConf the original column configuration. 415 * @param contentTypeId the content type ID. 416 * @param customCriterionId the custom criterion id 417 * @param group The group. Can be null. 418 * @return the configuration to provide to the custom criterion component. 419 * @throws ConfigurationException if an error occurs. 420 */ 421 protected Configuration getCustomCriteriaConfiguration(Configuration originalConf, String contentTypeId, String customCriterionId, I18nizableText group) throws ConfigurationException 422 { 423 DefaultConfiguration conf = new DefaultConfiguration(originalConf); 424 425 DefaultConfiguration customCriterionConf = new DefaultConfiguration("customCriterion"); 426 customCriterionConf.setAttribute("id", customCriterionId); 427 conf.addChild(customCriterionConf); 428 429 addContentTypesConfiguration(conf, contentTypeId); 430 431 if (group != null) 432 { 433 DefaultConfiguration groupConf = new DefaultConfiguration("group"); 434 groupConf.setAttribute("i18n", group.isI18n()); 435 groupConf.setValue(group.isI18n() ? group.getCatalogue() + ":" + group.getKey() : group.getLabel()); 436 conf.addChild(groupConf); 437 } 438 439 return conf; 440 } 441 442 /** 443 * Get the configuration of a metadata column component. 444 * @param contentTypeId the content type ID. 445 * @param metadataPath the metadata path. 446 * @return the configuration to provide to the metadata column component. 447 * @throws ConfigurationException if an error occurs. 448 */ 449 protected Configuration getMetadataColumnConfiguration(String contentTypeId, String metadataPath) throws ConfigurationException 450 { 451 return getMetadataColumnConfiguration(new DefaultConfiguration("column"), contentTypeId, metadataPath); 452 } 453 454 /** 455 * Get the configuration of a metadata column component. 456 * @param originalConf the original column configuration. 457 * @param contentTypeId the content type ID, may be null. 458 * @param metadataPath the metadata path. 459 * @return the configuration to provide to the metadata column component. 460 * @throws ConfigurationException if an error occurs. 461 */ 462 protected Configuration getMetadataColumnConfiguration(Configuration originalConf, String contentTypeId, String metadataPath) throws ConfigurationException 463 { 464 DefaultConfiguration conf = new DefaultConfiguration(originalConf); 465 466 DefaultConfiguration metaConf = new DefaultConfiguration("metadata"); 467 conf.addChild(metaConf); 468 metaConf.setAttribute("path", metadataPath); 469 470 addContentTypesConfiguration(conf, contentTypeId); 471 472 // conf for allowing sort on multiple join 473 DefaultConfiguration allowSortOnMultipleJoinConf = new DefaultConfiguration("allow-sort-on-multiple-join"); 474 allowSortOnMultipleJoinConf.setValue(allowSortOnMultipleJoin()); 475 conf.addChild(allowSortOnMultipleJoinConf); 476 477 return conf; 478 } 479 480 /** 481 * Get the configuration of a system column component. 482 * @param contentTypeId the content type ID. 483 * @param property the system property. 484 * @return the configuration to provide to the system column component. 485 * @throws ConfigurationException if an error occurs. 486 */ 487 protected Configuration getSystemColumnConfiguration(String contentTypeId, String property) throws ConfigurationException 488 { 489 return getSystemColumnConfiguration(new DefaultConfiguration("column"), contentTypeId, property); 490 } 491 492 /** 493 * Get the configuration of a system column component. 494 * @param originalConf the original column configuration. 495 * @param contentTypeId the content type ID. 496 * @param property the system property. 497 * @return the configuration to provide to the system column component. 498 * @throws ConfigurationException if an error occurs. 499 */ 500 protected Configuration getSystemColumnConfiguration(Configuration originalConf, String contentTypeId, String property) throws ConfigurationException 501 { 502 DefaultConfiguration conf = originalConf != null ? new DefaultConfiguration(originalConf) : new DefaultConfiguration("column"); 503 504 DefaultConfiguration propConf = new DefaultConfiguration("systemProperty"); 505 propConf.setAttribute("name", property); 506 conf.addChild(propConf); 507 508 addContentTypesConfiguration(conf, contentTypeId); 509 510 return conf; 511 } 512 513 /** 514 * Add the content types configuration. 515 * @param conf The configuration to write to. 516 * @param contentTypeId The "base" content type ID, may be null. 517 */ 518 protected void addContentTypesConfiguration(DefaultConfiguration conf, String contentTypeId) 519 { 520 Set<String> contentTypes = _searchModelHelper.getAllContentTypes(this, Collections.emptyMap()); 521 DefaultConfiguration cTypesConf = new DefaultConfiguration("contentTypes"); 522 conf.addChild(cTypesConf); 523 for (String contentType : contentTypes) 524 { 525 DefaultConfiguration cTypeConf = new DefaultConfiguration("type"); 526 cTypeConf.setAttribute("id", contentType); 527 cTypesConf.addChild(cTypeConf); 528 } 529 530 if (contentTypeId != null) 531 { 532 cTypesConf.setAttribute("baseId", contentTypeId); 533 } 534 } 535 536}