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