001/* 002 * Copyright 2016 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.cms.explorer; 017 018import java.io.IOException; 019import java.util.ArrayList; 020import java.util.List; 021import java.util.Map; 022 023import org.apache.avalon.framework.service.ServiceException; 024import org.apache.avalon.framework.service.ServiceManager; 025import org.apache.cocoon.ProcessingException; 026import org.apache.cocoon.environment.ObjectModelHelper; 027import org.apache.cocoon.environment.Request; 028import org.apache.cocoon.xml.XMLUtils; 029import org.apache.commons.lang.StringUtils; 030import org.apache.solr.client.solrj.util.ClientUtils; 031import org.xml.sax.SAXException; 032 033import org.ametys.cms.content.indexing.solr.SolrFieldNames; 034import org.ametys.cms.search.Sort; 035import org.ametys.cms.search.Sort.Order; 036import org.ametys.cms.search.query.AndQuery; 037import org.ametys.cms.search.query.DocumentTypeQuery; 038import org.ametys.cms.search.query.DublinCoreQuery; 039import org.ametys.cms.search.query.FilenameQuery; 040import org.ametys.cms.search.query.FullTextQuery; 041import org.ametys.cms.search.query.NotQuery; 042import org.ametys.cms.search.query.OrQuery; 043import org.ametys.cms.search.query.Query; 044import org.ametys.cms.search.query.Query.Operator; 045import org.ametys.cms.search.query.QuerySyntaxException; 046import org.ametys.cms.search.query.ResourceLocationQuery; 047import org.ametys.cms.search.query.UsersQuery; 048import org.ametys.cms.search.solr.SearcherFactory; 049import org.ametys.core.user.UserIdentity; 050import org.ametys.core.util.JSONUtils; 051import org.ametys.plugins.core.user.UserHelper; 052import org.ametys.plugins.explorer.ExplorerNode; 053import org.ametys.plugins.explorer.resources.Resource; 054import org.ametys.plugins.explorer.resources.generators.SearchGenerator; 055import org.ametys.plugins.repository.AmetysObjectIterable; 056 057/** 058 * Search resources in a specific explorer node. 059 */ 060public class SearchResourcesGenerator extends SearchGenerator 061{ 062 /** The searcher factory. */ 063 protected SearcherFactory _searcherFactory; 064 065 /** The JSON utils */ 066 protected JSONUtils _jsonUtils; 067 068 /** The user helper */ 069 protected UserHelper _userHelper; 070 071 @Override 072 public void service(ServiceManager sManager) throws ServiceException 073 { 074 super.service(sManager); 075 _searcherFactory = (SearcherFactory) sManager.lookup(SearcherFactory.ROLE); 076 _jsonUtils = (JSONUtils) sManager.lookup(JSONUtils.ROLE); 077 _userHelper = (UserHelper) manager.lookup(UserHelper.ROLE); 078 } 079 080 @Override 081 public void generate() throws IOException, SAXException, ProcessingException 082 { 083 Request request = ObjectModelHelper.getRequest(objectModel); 084 085 String id = request.getParameter("id"); 086 String rootId = request.getParameter("rootId"); 087 ExplorerNode node = _resolver.resolveById(id); 088 089 Query query = getQuery(request, node, rootId); 090 091 contentHandler.startDocument(); 092 XMLUtils.startElement(contentHandler, "resources"); 093 094 try 095 { 096 Sort sort = new Sort(SolrFieldNames.TITLE_SORT, Order.ASC); 097 098 AmetysObjectIterable<Resource> resources = _searcherFactory.create() 099 .withQuery(query) 100 .withFilterQueries(new DocumentTypeQuery(SolrFieldNames.TYPE_RESOURCE)) 101 .withSort(sort) 102 .search(); 103 104 for (Resource resource : resources) 105 { 106 saxResource(resource); 107 } 108 } 109 catch (Exception e) 110 { 111 getLogger().error("Error searching resources in the explorer node " + id, e); 112 throw new ProcessingException("Error searching resources in the explorer node " + id, e); 113 } 114 115 XMLUtils.endElement(contentHandler, "resources"); 116 contentHandler.endDocument(); 117 } 118 119 /** 120 * Build the query object corresponding to the user search. 121 * @param request The user request. 122 * @param explorerNode The explorer node to search into. 123 * @param rootId The root ID, can be null to search all resources. 124 * @return the query object. 125 */ 126 protected Query getQuery(Request request, ExplorerNode explorerNode, String rootId) 127 { 128 List<Query> queries = new ArrayList<>(); 129 130 if (explorerNode != null || StringUtils.isNotEmpty(rootId)) 131 { 132 String path = explorerNode == null ? "" : explorerNode.getExplorerPath(); 133 queries.add(new ResourceLocationQuery(rootId, path)); 134 } 135 136 // File name 137 String name = request.getParameter("name"); 138 if (StringUtils.isNotEmpty(name)) 139 { 140 queries.add(new FilenameQuery(name)); 141 } 142 143 // Full text 144 String fulltext = request.getParameter("fulltext"); 145 if (StringUtils.isNotEmpty(fulltext)) 146 { 147 queries.add(new FullTextQuery(fulltext, Operator.LIKE)); 148 } 149 150 String keywords = request.getParameter("keywords"); 151 if (StringUtils.isNotEmpty(keywords)) 152 { 153 Query subjectQuery = new DublinCoreQuery("subject", keywords); 154 Query descQuery = new DublinCoreQuery("description", keywords); 155 156 queries.add(new OrQuery(subjectQuery, descQuery)); 157 } 158 159 String authorAsStr = request.getParameter("author"); 160 Map<String, Object> json = _jsonUtils.convertJsonToMap(authorAsStr); 161 UserIdentity author = _userHelper.json2userIdentity(json); 162 if (null != author) 163 { 164 queries.add(new UsersQuery(SolrFieldNames.RESOURCE_CREATOR, author)); 165 } 166 167 return new AndQuery(queries); 168 } 169 170 171 172 /** 173 * Represents a {@link Query} testing the resource creator. 174 */ 175 class ResourceCreatorQuery implements Query 176 { 177 /** The operator. */ 178 private Operator _operator; 179 180 /** The value to test. */ 181 private String _value; 182 183 /** 184 * Build a string query. 185 * @param value the value. 186 */ 187 public ResourceCreatorQuery(String value) 188 { 189 this(Operator.EQ, value); 190 } 191 192 /** 193 * Build a string query. 194 * @param op the operator. 195 * @param value the value. 196 */ 197 public ResourceCreatorQuery(Operator op, String value) 198 { 199 _operator = op; 200 _value = value; 201 } 202 203 @Override 204 public String build() throws QuerySyntaxException 205 { 206 StringBuilder query = new StringBuilder(); 207 208 if (_operator == Operator.NE) 209 { 210 NotQuery.appendNegation(query); 211 } 212 213 query.append(SolrFieldNames.RESOURCE_CREATOR).append(':') 214 .append(ClientUtils.escapeQueryChars(_value)); 215 216 return query.toString(); 217 } 218 219 @Override 220 public int hashCode() 221 { 222 final int prime = 31; 223 int result = 1; 224 result = prime * result + _getOuterType().hashCode(); 225 result = prime * result + ((_operator == null) ? 0 : _operator.hashCode()); 226 result = prime * result + ((_value == null) ? 0 : _value.hashCode()); 227 return result; 228 } 229 230 @Override 231 public boolean equals(Object obj) 232 { 233 if (this == obj) 234 { 235 return true; 236 } 237 if (obj == null) 238 { 239 return false; 240 } 241 if (getClass() != obj.getClass()) 242 { 243 return false; 244 } 245 ResourceCreatorQuery other = (ResourceCreatorQuery) obj; 246 if (!_getOuterType().equals(other._getOuterType())) 247 { 248 return false; 249 } 250 if (_operator != other._operator) 251 { 252 return false; 253 } 254 if (_value == null) 255 { 256 if (other._value != null) 257 { 258 return false; 259 } 260 } 261 else if (!_value.equals(other._value)) 262 { 263 return false; 264 } 265 return true; 266 } 267 268 private SearchResourcesGenerator _getOuterType() 269 { 270 return SearchResourcesGenerator.this; 271 } 272 } 273}