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.web.search.misc; 017 018import java.util.Arrays; 019import java.util.List; 020import java.util.Map; 021 022import org.apache.avalon.framework.component.Component; 023import org.apache.avalon.framework.context.Context; 024import org.apache.avalon.framework.context.ContextException; 025import org.apache.avalon.framework.context.Contextualizable; 026import org.apache.avalon.framework.service.ServiceException; 027import org.apache.avalon.framework.service.ServiceManager; 028import org.apache.avalon.framework.service.Serviceable; 029import org.apache.cocoon.components.ContextHelper; 030import org.apache.cocoon.environment.Request; 031import org.apache.commons.lang3.StringUtils; 032 033import org.ametys.cms.search.query.AndQuery; 034import org.ametys.cms.search.query.NotQuery; 035import org.ametys.cms.search.query.Query; 036import org.ametys.cms.search.query.Query.Operator; 037import org.ametys.core.util.JSONUtils; 038import org.ametys.runtime.model.exception.BadItemTypeException; 039import org.ametys.web.repository.site.Site; 040import org.ametys.web.search.query.SiteQuery; 041 042/** 043 * Helper for getting a {@link SiteQuery} from a user-submitted value. 044 */ 045public class SiteQueryHelper implements Component, Serviceable, Contextualizable 046{ 047 /** Avalon Role */ 048 public static final String ROLE = SiteQueryHelper.class.getName(); 049 050 private JSONUtils _jsonUtils; 051 private Context _context; 052 053 @Override 054 public void contextualize(Context context) throws ContextException 055 { 056 _context = context; 057 } 058 059 @Override 060 public void service(ServiceManager manager) throws ServiceException 061 { 062 _jsonUtils = (JSONUtils) manager.lookup(JSONUtils.ROLE); 063 } 064 065 /** 066 * Gets a {@link Query} testing {@link Site} from a user-submitted value 067 * @param value a user-submitted value 068 * @param operator The operator 069 * @param criterionId The criterion id (for logging purposes only) 070 * @param contextualParameters the search contextual parameters. 071 * @return The {@link Query} 072 */ 073 @SuppressWarnings("unchecked") 074 public Query getQuery(Object value, Operator operator, String criterionId, Map<String, Object> contextualParameters) 075 { 076 // Handles a list of given site names (SITES_LIST) as well as "CURRENT_SITE", "OTHER_SITES" and "SITES" (all sites). 077 Map<String, Object> valueMap = _parseSite(value, criterionId); 078 String context = (String) valueMap.get("context"); 079 080 Request request = ContextHelper.getRequest(_context); 081 String currentSite = (String) request.getAttribute("siteName"); 082 if (StringUtils.isBlank(currentSite)) 083 { 084 currentSite = (String) contextualParameters.get("siteName"); 085 } 086 087 if ("CURRENT_SITE".equals(context)) 088 { 089 return new SiteQuery(operator, currentSite); 090 } 091 else if ("OTHER_SITES".equals(context)) 092 { 093 // other sites than current one 094 // so 'normal case' (i.e. operator = EQ) is testing <NE current_site> 095 // and 'NE case' is testing the opposite (site is not equal to other sites), <EQ current_site> 096 return new AndQuery( 097 new SiteQuery(), 098 new SiteQuery(Operator.NE == operator 099 ? Operator.EQ 100 : Operator.NE 101 , currentSite)); 102 } 103 else if ("SITES".equals(context)) 104 { 105 return Operator.NE == operator 106 ? new NotQuery(new SiteQuery()) 107 : new SiteQuery(); 108 } 109 110 // "SITES_LIST" context: get the site list from the value map. 111 List<String> names = (List<String>) valueMap.get("sites"); 112 113 // Standard context: site list. 114 return new SiteQuery(operator, names); 115 } 116 117 /** 118 * Converts the given site value to have {@link Map} containing site context and value 119 * @param value the value to convert 120 * @param criterionId The criterion id (for logging purposes only) 121 * @return the value, converted to a {@link Map} 122 * @throws BadItemTypeException if the given value can not be converted 123 */ 124 private Map<String, Object> _parseSite(Object value, String criterionId) throws BadItemTypeException 125 { 126 if (value == null) 127 { 128 return null; 129 } 130 else if (value instanceof String) 131 { 132 String strValue = (String) value; 133 if (strValue.startsWith("{")) 134 { 135 // Usually when coming from BO site widget 136 return _jsonUtils.convertJsonToMap(strValue); 137 } 138 else if ("CURRENT_SITE".equals(strValue) || "OTHER_SITES".equals(strValue) || "SITES".equals(strValue)) 139 { 140 return Map.of("context", strValue); 141 } 142 else 143 { 144 // Consider it as the list of sites itself 145 return Map.of( 146 "context", "SITES_LIST", 147 "sites", Arrays.asList(strValue.split(",")) 148 ); 149 } 150 } 151 else if (value instanceof String[] arrayValue) 152 { 153 // Consider it as the list of sites itself 154 // Coming from all options of search service criterion 155 return Map.of( 156 "context", "SITES_LIST", 157 "sites", Arrays.asList(arrayValue) 158 ); 159 } 160 else 161 { 162 throw new BadItemTypeException("The value " + value + " for criterion " + criterionId + " is not a valid Site value."); 163 } 164 } 165} 166