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