001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.jsp.search.config.parser.simplesearch.preconfiguredrestrictions; 029 030import org.opencms.jsp.search.config.parser.simplesearch.preconfiguredrestrictions.CmsRestrictionRule.MatchType; 031import org.opencms.jsp.search.config.parser.simplesearch.preconfiguredrestrictions.CmsRestrictionsBean.FieldValues.FieldType; 032import org.opencms.main.CmsException; 033import org.opencms.main.CmsLog; 034 035import java.util.Arrays; 036import java.util.Collection; 037import java.util.Collections; 038import java.util.HashMap; 039import java.util.HashSet; 040import java.util.Map; 041import java.util.stream.Collectors; 042 043import org.apache.commons.logging.Log; 044import org.apache.solr.client.solrj.util.ClientUtils; 045 046/** Wraps the preconfigured restrictions. */ 047public class CmsRestrictionsBean { 048 049 /** The values in one input field. */ 050 public static class FieldValues { 051 052 /** The type describes how values in that input field should be handled. */ 053 public static enum FieldType { 054 /** Use the value as plain Solr input. */ 055 PLAIN, 056 /** Use the values in the default way, that is according to the rule configuration. */ 057 DEFAULT 058 } 059 060 /** The field type. */ 061 private FieldType m_type; 062 /** The values in the field. */ 063 private Collection<String> m_values; 064 065 /** 066 * Default constructor. 067 * @param type the field type. 068 * @param values the field values. 069 */ 070 public FieldValues(FieldType type, Collection<String> values) { 071 072 m_type = type; 073 m_values = Collections.unmodifiableCollection(values); 074 } 075 076 /** 077 * Returns the type of the input field. 078 * @return the type of the input field. 079 */ 080 public FieldType getFieldType() { 081 082 return m_type; 083 } 084 085 /** 086 * Returns the values in the input field. 087 * @return the values in the input field. 088 */ 089 public Collection<String> getValues() { 090 091 return m_values; 092 } 093 } 094 095 /** The logger for this class. */ 096 private static final Log LOG = CmsLog.getLog(CmsRestrictionsBean.class.getName()); 097 098 /** Constant for the rule to ignore. */ 099 private static final String CONST_IGNORED_RULE = "none"; 100 101 /** Constant for the rule rule prefix, if the rule should be just used as plain solr query. */ 102 private static final String PREFIX_PLAIN = "plain:"; 103 104 /** 105 * Map from type to rule to values for the rule. 106 * We use this structure to easily generate the solr queries. 107 */ 108 private Map<String, Map<CmsRestrictionRule, Collection<FieldValues>>> m_restrictions = new HashMap<>(); 109 110 /** 111 * Add a preconfigured restriction. 112 * @param ruleString the rule for the restriction. 113 * @param values the values for the restriction. 114 */ 115 public void addRestriction(String ruleString, Collection<String> values) { 116 117 // Filter out empty values. 118 Collection<String> realValues = values.stream().map( 119 v -> (v == null) || (v.trim().length() == 0) ? null : v.trim()).filter(v -> v != null).collect( 120 Collectors.toSet()); 121 if (realValues.size() > 0) { 122 CmsRestrictionRule rule = null; 123 // This rule has to be ignored - so we do not parse it at all. 124 if (CONST_IGNORED_RULE.equals(ruleString)) { 125 return; 126 } 127 try { 128 rule = CmsRestrictionRuleParser.parseRule(ruleString); 129 } catch (CmsException e) { 130 LOG.warn("Ignoring unparsable restriction rule '" + ruleString + "'.", e); 131 return; 132 } 133 // We know the rule is parsed and ok here. 134 String type = rule.getType(); 135 if (null == m_restrictions.get(type)) { 136 m_restrictions.put(type, new HashMap<>()); 137 } 138 Map<CmsRestrictionRule, Collection<FieldValues>> mapForType = m_restrictions.get(type); 139 Collection<FieldValues> fieldValues = new HashSet<>(realValues.size()); 140 for (String value : realValues) { 141 if (value.startsWith(PREFIX_PLAIN)) { 142 String realValue = value.substring(PREFIX_PLAIN.length()).trim(); 143 fieldValues.add(new FieldValues(FieldValues.FieldType.PLAIN, Collections.singleton(realValue))); 144 } else if (rule.getMatchType().equals(MatchType.EXACT)) { 145 fieldValues.add( 146 new FieldValues(FieldType.DEFAULT, Collections.singleton(ClientUtils.escapeQueryChars(value)))); 147 } else { 148 Collection<String> finalValues = (Arrays.asList(value.split(" "))).stream().map( 149 word -> ClientUtils.escapeQueryChars(word.trim())).collect(Collectors.toSet()); 150 fieldValues.add(new FieldValues(FieldValues.FieldType.DEFAULT, finalValues)); 151 } 152 } 153 mapForType.put(rule, fieldValues); 154 } else { 155 LOG.debug("Ignoring restriction with rule '" + ruleString + "' since no real values are provided."); 156 } 157 } 158 159 /** 160 * Returns the restrictions for the provided type. 161 * @param type the type to get the restrictions for. 162 * @return the restrictions for the provided type. 163 */ 164 public Map<CmsRestrictionRule, Collection<FieldValues>> getRestrictionsForType(String type) { 165 166 return m_restrictions.get(type); 167 } 168 169 /** 170 * Returns a flag, indicating if there are restrictions for the provided type. 171 * @param type the type to check. 172 * @return <code>true</code> iff there are restrictions for the provided type, <code>false</otherwise>. 173 */ 174 public boolean hasRestrictionForType(String type) { 175 176 // If it's not null, it can't be empty since it can only be filled via addRestriction 177 return null != m_restrictions.get(type); 178 } 179 180 /** 181 * Returns a flag, indicating if there are restrictions at all. 182 * @return <code>true</code> iff there are restrictions, <code>false</otherwise>. 183 */ 184 public boolean hasRestrictions() { 185 186 return m_restrictions.size() > 0; 187 } 188}