001/* 002 * Copyright 2019 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.plugins.odfweb.service.search; 017 018import java.util.Arrays; 019import java.util.Collection; 020import java.util.Collections; 021import java.util.Map; 022import java.util.Optional; 023 024import org.apache.avalon.framework.service.ServiceException; 025import org.apache.avalon.framework.service.ServiceManager; 026 027import org.ametys.cms.search.advanced.AbstractTreeNode; 028import org.ametys.cms.search.query.AndQuery; 029import org.ametys.cms.search.query.ConstantNilScoreQuery; 030import org.ametys.cms.search.query.ContentTypeQuery; 031import org.ametys.cms.search.query.IsolateQuery; 032import org.ametys.cms.search.query.JoinQuery; 033import org.ametys.cms.search.query.MaxScoreOrQuery; 034import org.ametys.cms.search.query.Query; 035import org.ametys.odf.program.Program; 036import org.ametys.odf.program.ProgramFactory; 037import org.ametys.odf.program.SubProgramFactory; 038import org.ametys.odf.program.TraversableProgramPart; 039import org.ametys.plugins.odfweb.service.search.criterion.DegreeUniversityAttributeContentSearchCriterionDefinition; 040import org.ametys.plugins.odfweb.service.search.helper.DegreeUniversityHelper; 041import org.ametys.web.frontoffice.search.instance.model.FOSearchCriterion; 042import org.ametys.web.frontoffice.search.metamodel.AdditionalParameterValueMap; 043import org.ametys.web.frontoffice.search.metamodel.Returnable; 044import org.ametys.web.frontoffice.search.metamodel.SearchCriterionDefinition; 045import org.ametys.web.frontoffice.search.metamodel.Searchable; 046import org.ametys.web.frontoffice.search.metamodel.impl.AbstractContentBasedSearchable; 047 048/** 049 * {@link Searchable} for {@link Program}s 050 */ 051public class ProgramSearchable extends AbstractContentBasedSearchable 052{ 053 /** Avalon Role */ 054 public static final String ROLE = ProgramSearchable.class.getName(); 055 056 /** The additional parameter for indicating if search has to be made also on subprograms */ 057 public static final String PARAMETER_SEARCH_ON_SUBPROGRAMS = "searchSubprogram"; 058 059 /** The prefix for program searchable */ 060 public static final String CRITERION_DEFINITIONS_PREFIX_ID = "ProgramSearchable$"; 061 062 /** The prefix for indexing field in program searcheable */ 063 public static final String PROGRAM_SEARCHEABLE_INDEXING_FIELD_PREFIX = CRITERION_DEFINITIONS_PREFIX_ID + "indexingField$" + ProgramFactory.PROGRAM_CONTENT_TYPE + "$"; 064 065 /** The degree university helper */ 066 protected DegreeUniversityHelper _degreeUniversityHelper; 067 068 @Override 069 public void service(ServiceManager manager) throws ServiceException 070 { 071 super.service(manager); 072 _degreeUniversityHelper = (DegreeUniversityHelper) manager.lookup(DegreeUniversityHelper.ROLE); 073 } 074 075 @Override 076 protected String associatedContentReturnableRole() 077 { 078 return ProgramReturnable.ROLE; 079 } 080 081 @Override 082 protected String getCriterionDefinitionPrefix() 083 { 084 return CRITERION_DEFINITIONS_PREFIX_ID; 085 } 086 087 @Override 088 public Collection<Returnable> relationsWith() 089 { 090 return Arrays.asList(_associatedContentReturnable); 091 } 092 093 @Override 094 protected Collection<String> getContentTypes(AdditionalParameterValueMap additionalParameterValues) 095 { 096 return Collections.singleton(ProgramFactory.PROGRAM_CONTENT_TYPE); 097 } 098 099 @Override 100 public Optional<Query> joinQuery(Query queryOnCriterion, SearchCriterionDefinition criterion, Collection<Returnable> returnables, AdditionalParameterValueMap additionalParameters) 101 { 102 if (returnables.contains(_associatedContentReturnable)) 103 { 104 return Optional.of(queryOnCriterion); 105 } 106 return Optional.empty(); 107 } 108 109 @Override 110 public Query buildQuery( 111 AbstractTreeNode<FOSearchCriterion> criterionTree, 112 Map<String, Object> userCriteria, 113 Collection<Returnable> returnables, 114 Collection<Searchable> searchables, 115 AdditionalParameterValueMap additionalParameters, 116 String currentLang, 117 Map<String, Object> contextualParameters) 118 { 119 Query query = super.buildQuery(criterionTree, userCriteria, returnables, searchables, additionalParameters, currentLang, contextualParameters); 120 if (_searchOnSubprograms(additionalParameters)) 121 { 122 // This query search on 123 // - programs matching user criteria 124 // OR 125 // - subprograms matching user criteria 126 // This is the same query because it is assumed that programs and subprograms have the same attributes (properties are added for subprogram to match with missing program attributes) 127 return new MaxScoreOrQuery( 128 new IsolateQuery(query), 129 getProgramThroughSubprogramsQuery(query) 130 ); 131 } 132 else 133 { 134 return query; 135 } 136 } 137 138 private boolean _searchOnSubprograms(AdditionalParameterValueMap additionalParameters) 139 { 140 return additionalParameters.getValue(PARAMETER_SEARCH_ON_SUBPROGRAMS); 141 } 142 143 /** 144 * Gets the {@link Query} that returns Programs by querying their SubPrograms 145 * @param queryOnCriterion The query on SubPrograms 146 * @return The {@link Query} that returns Programs 147 */ 148 protected Query getProgramThroughSubprogramsQuery(Query queryOnCriterion) 149 { 150 Query queryOnSubprograms = new AndQuery( 151 new ConstantNilScoreQuery(new ContentTypeQuery(SubProgramFactory.SUBPROGRAM_CONTENT_TYPE)), 152 queryOnCriterion 153 ); 154 return new ProgramThroughProgramPartsQuery(queryOnSubprograms); 155 } 156 157 @Override 158 public Collection<SearchCriterionDefinition> getCriteria(AdditionalParameterValueMap additionalParameterValues) 159 { 160 Collection<SearchCriterionDefinition> criteria = super.getCriteria(additionalParameterValues); 161 162 DegreeUniversityAttributeContentSearchCriterionDefinition degreeUniversityCriterionDefinition = _degreeUniversityHelper.getDegreeUniversityCriterionDefinition(this); 163 if (degreeUniversityCriterionDefinition != null) 164 { 165 criteria.add(degreeUniversityCriterionDefinition); 166 } 167 168 return criteria; 169 } 170 171 /** 172 * A {@link Query} that returns Programs, by querying their child ProgramParts 173 */ 174 protected static class ProgramThroughProgramPartsQuery extends JoinQuery 175 { 176 /** 177 * Builds a ProgramThroughProgramPartsQuery 178 * @param subQuery The query on ProgramParts 179 */ 180 protected ProgramThroughProgramPartsQuery(Query subQuery) 181 { 182 super(subQuery, TraversableProgramPart.CHILD_PROGRAM_PARTS); 183 } 184 } 185}