001/* 002 * Copyright 2020 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.web.frontoffice.search.metamodel.impl; 017 018import java.util.ArrayList; 019import java.util.Collection; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023import java.util.Objects; 024import java.util.stream.Collectors; 025 026import org.apache.avalon.framework.service.ServiceException; 027 028import org.ametys.cms.data.type.indexing.IndexableElementType; 029import org.ametys.cms.search.query.NotQuery; 030import org.ametys.cms.search.query.OrQuery; 031import org.ametys.cms.search.query.Query; 032import org.ametys.cms.search.query.Query.Operator; 033import org.ametys.plugins.repository.AmetysObjectResolver; 034import org.ametys.plugins.repository.UnknownAmetysObjectException; 035import org.ametys.runtime.i18n.I18nizableText; 036import org.ametys.runtime.model.type.ModelItemTypeConstants; 037import org.ametys.runtime.parameter.DefaultValidator; 038import org.ametys.runtime.parameter.Validator; 039import org.ametys.web.frontoffice.search.metamodel.RestrictedEnumerator; 040import org.ametys.web.frontoffice.search.metamodel.SearchServiceCriterionDefinition; 041import org.ametys.web.repository.page.Page; 042import org.ametys.web.search.query.PageQuery; 043 044/** 045 * {@link SearchServiceCriterionDefinition} proposing a criterion definition on the page of the indexed document. 046 */ 047public class PageCriterionDefinition extends AbstractSearchServiceCriterionDefinition<String> 048{ 049 /** The ametys object resolver */ 050 private AmetysObjectResolver _resolver; 051 052 @Override 053 protected boolean isTooBigForStaticEnumerator() 054 { 055 return true; 056 } 057 058 @Override 059 public RestrictedEnumerator<String> getRestrictedEnumerator(Map<String, Object> contextualParameters) 060 { 061 return new PageEnumeratedValues(_getAmetysObjectResolver()); 062 } 063 064 @Override 065 public String getWidget() 066 { 067 return "edition.select-page"; 068 } 069 070 @Override 071 public Map<String, I18nizableText> getWidgetParameters() 072 { 073 Map<String, I18nizableText> parameters = new HashMap<>(); 074 parameters.put("siteContext", new I18nizableText("all")); 075 076 return parameters; 077 } 078 079 @SuppressWarnings("unchecked") 080 @Override 081 public IndexableElementType<String> getType() 082 { 083 String typeId = ModelItemTypeConstants.STRING_TYPE_ID; 084 return (IndexableElementType<String>) _getCriterionTypeExtensionPoint().getExtension(typeId); 085 } 086 087 @Override 088 public Query getQuery(Object value, Operator operator, Map<String, Object> allValues, String language, Map<String, Object> contextualParameters) 089 { 090 String[] pageIds; 091 if (value instanceof String) 092 { 093 pageIds = ((String) value).split(","); 094 } 095 else if (value instanceof Collection<?>) 096 { 097 pageIds = ((Collection<?>) value) 098 .stream() 099 .filter(String.class::isInstance) 100 .map(String.class::cast) 101 .toArray(String[]::new); 102 } 103 else 104 { 105 throw new IllegalArgumentException("Not handled type of value: '" + value + "'"); 106 } 107 108 List<Query> queries = new ArrayList<>(); 109 for (String pageId : pageIds) 110 { 111 queries.add(new PageQuery(pageId, true)); 112 } 113 114 OrQuery orQuery = new OrQuery(queries); 115 return operator == Operator.NE ? new NotQuery(orQuery) : orQuery; 116 } 117 118 static class PageEnumeratedValues implements RestrictedEnumerator<String> 119 { 120 /** The ametys object resolver */ 121 private AmetysObjectResolver _resolver; 122 123 public PageEnumeratedValues(AmetysObjectResolver resolver) 124 { 125 this._resolver = resolver; 126 } 127 128 public Map<String, I18nizableText> getEntries() throws Exception 129 { 130 // Never calculate all values because too many page can be display 131 return new HashMap<>(); 132 } 133 134 public RestrictedValues<String> getRestrictedEntriesFor(List<String> objs) 135 { 136 return new PageRestrictedValues(objs, this._resolver); 137 } 138 139 static class PageRestrictedValues implements RestrictedValues<String> 140 { 141 private List<String> _forObjs; 142 private AmetysObjectResolver _resolver; 143 144 PageRestrictedValues(List<String> forObjs, AmetysObjectResolver resolver) 145 { 146 this._forObjs = forObjs; 147 this._resolver = resolver; 148 } 149 150 @Override 151 public Map<String, I18nizableText> values() 152 { 153 return this._forObjs.stream() 154 .filter(String.class::isInstance) 155 .map(String.class::cast) 156 .map(this::_getPage) 157 .filter(Objects::nonNull) 158 .collect(Collectors.toMap(Page::getId, page -> new I18nizableText(page.getTitle()))); 159 } 160 161 private Page _getPage(String pageId) 162 { 163 try 164 { 165 return this._resolver.resolveById(pageId); 166 } 167 catch (UnknownAmetysObjectException e) 168 { 169 return null; 170 } 171 } 172 } 173 } 174 175 @Override 176 public Validator getValidator() 177 { 178 return new DefaultValidator(null, true); 179 } 180 181 @Override 182 public Query getEmptyValueQuery(String language, Map<String, Object> contextualParameters) 183 { 184 throw new UnsupportedOperationException("This method should not be called on the criteria PageCriterionDefinition"); 185 } 186 187 /** 188 * Retrieves the {@link AmetysObjectResolver} 189 * @return the {@link AmetysObjectResolver} 190 */ 191 protected AmetysObjectResolver _getAmetysObjectResolver() 192 { 193 if (_resolver == null) 194 { 195 try 196 { 197 _resolver = (AmetysObjectResolver) __serviceManager.lookup(AmetysObjectResolver.ROLE); 198 } 199 catch (ServiceException e) 200 { 201 throw new RuntimeException("Unable to lookup after the ametys object resolver", e); 202 } 203 } 204 205 return _resolver; 206 } 207}