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