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.Optional; 022 023import org.apache.avalon.framework.service.ServiceException; 024import org.apache.avalon.framework.service.ServiceManager; 025 026import org.ametys.cms.search.query.AndQuery; 027import org.ametys.cms.search.query.ConstantNilScoreQuery; 028import org.ametys.cms.search.query.ContentTypeQuery; 029import org.ametys.cms.search.query.IsolateQuery; 030import org.ametys.cms.search.query.JoinQuery; 031import org.ametys.cms.search.query.MaxScoreOrQuery; 032import org.ametys.cms.search.query.Query; 033import org.ametys.odf.program.Program; 034import org.ametys.odf.program.ProgramFactory; 035import org.ametys.odf.program.SubProgramFactory; 036import org.ametys.odf.program.TraversableProgramPart; 037import org.ametys.web.frontoffice.search.metamodel.AdditionalParameterValueMap; 038import org.ametys.web.frontoffice.search.metamodel.Returnable; 039import org.ametys.web.frontoffice.search.metamodel.SearchCriterionDefinition; 040import org.ametys.web.frontoffice.search.metamodel.Searchable; 041import org.ametys.web.frontoffice.search.metamodel.impl.AbstractContentBasedSearchable; 042 043/** 044 * {@link Searchable} for {@link Program}s 045 */ 046public class ProgramSearchable extends AbstractContentBasedSearchable 047{ 048 /** Avalon Role */ 049 public static final String ROLE = ProgramSearchable.class.getName(); 050 051 /** The additional parameter for indicating if search has to be made also on subprograms */ 052 public static final String PARAMETER_SEARCH_ON_SUBPROGRAMS = "searchSubprogram"; 053 054 private static final String __CRITERION_DEFINITIONS_PREFIX_ID = "ProgramSearchable$"; 055 056 /** The ODF search helper */ 057 protected ODFSearchHelper _odfSearchHelper; 058 059 @Override 060 public void service(ServiceManager manager) throws ServiceException 061 { 062 super.service(manager); 063 _odfSearchHelper = (ODFSearchHelper) manager.lookup(ODFSearchHelper.ROLE); 064 } 065 066 @Override 067 protected String associatedContentReturnableRole() 068 { 069 return ProgramReturnable.ROLE; 070 } 071 072 @Override 073 protected String getCriterionDefinitionPrefix() 074 { 075 return __CRITERION_DEFINITIONS_PREFIX_ID; 076 } 077 078 @Override 079 public Collection<Returnable> relationsWith() 080 { 081 return Arrays.asList(_associatedContentReturnable); 082 } 083 084 @Override 085 protected Collection<String> getContentTypes(AdditionalParameterValueMap additionalParameterValues) 086 { 087 return Collections.singleton(ProgramFactory.PROGRAM_CONTENT_TYPE); 088 } 089 090 @Override 091 public Optional<Query> joinQuery(Query queryOnCriterion, SearchCriterionDefinition criterion, Collection<Returnable> returnables, AdditionalParameterValueMap additionalParameters) 092 { 093 if (returnables.contains(_associatedContentReturnable)) 094 { 095 if (_searchOnSubprograms(additionalParameters) && appliesToSubprogram(criterion)) 096 { 097 return Optional.of(new MaxScoreOrQuery(new IsolateQuery(queryOnCriterion), getProgramThroughSubprogramsQuery(queryOnCriterion))); 098 } 099 else 100 { 101 return Optional.of(queryOnCriterion); 102 } 103 } 104 else 105 { 106 return Optional.empty(); 107 } 108 } 109 110 private boolean _searchOnSubprograms(AdditionalParameterValueMap additionalParameters) 111 { 112 return additionalParameters.getValue(PARAMETER_SEARCH_ON_SUBPROGRAMS); 113 } 114 115 /** 116 * Determines if the given {@link SearchCriterionDefinition} applies to Subprograms 117 * @param criterion the criterion 118 * @return <code>true</code> if the given {@link SearchCriterionDefinition} applies to Subprograms 119 */ 120 protected boolean appliesToSubprogram(SearchCriterionDefinition criterion) 121 { 122 return _odfSearchHelper.isCriterionOnBothProgramAndSubProgram(criterion); 123 } 124 125 /** 126 * Gets the {@link Query} that returns Programs by querying their SubPrograms 127 * @param queryOnCriterion The query on SubPrograms 128 * @return The {@link Query} that returns Programs 129 */ 130 protected Query getProgramThroughSubprogramsQuery(Query queryOnCriterion) 131 { 132 Query queryOnSubprograms = new AndQuery( 133 new ConstantNilScoreQuery(new ContentTypeQuery(SubProgramFactory.SUBPROGRAM_CONTENT_TYPE)), 134 queryOnCriterion 135 ); 136 return new ProgramThroughProgramPartsQuery(queryOnSubprograms); 137 } 138 139 /** 140 * A {@link Query} that returns Programs, by querying their child ProgramParts 141 */ 142 protected static class ProgramThroughProgramPartsQuery extends JoinQuery 143 { 144 /** 145 * Builds a ProgramThroughProgramPartsQuery 146 * @param subQuery The query on ProgramParts 147 */ 148 protected ProgramThroughProgramPartsQuery(Query subQuery) 149 { 150 super(subQuery, TraversableProgramPart.CHILD_PROGRAM_PARTS); 151 } 152 } 153}