001/* 002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 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 * 016 * Contributors: 017 * Thierry Delprat 018 */ 019package org.nuxeo.ecm.automation.core.operations.services; 020 021import java.io.Serializable; 022import java.util.ArrayList; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026 027import org.apache.commons.lang.StringUtils; 028import org.apache.commons.logging.Log; 029import org.apache.commons.logging.LogFactory; 030import org.nuxeo.ecm.automation.OperationContext; 031import org.nuxeo.ecm.automation.OperationException; 032import org.nuxeo.ecm.automation.core.Constants; 033import org.nuxeo.ecm.automation.core.annotations.Context; 034import org.nuxeo.ecm.automation.core.annotations.Operation; 035import org.nuxeo.ecm.automation.core.annotations.OperationMethod; 036import org.nuxeo.ecm.automation.core.annotations.Param; 037import org.nuxeo.ecm.automation.core.util.Properties; 038import org.nuxeo.ecm.automation.core.util.RecordSet; 039import org.nuxeo.ecm.automation.core.util.StringList; 040import org.nuxeo.ecm.core.api.CoreSession; 041import org.nuxeo.ecm.core.api.DocumentModel; 042import org.nuxeo.ecm.core.api.SortInfo; 043import org.nuxeo.ecm.core.query.sql.NXQL; 044import org.nuxeo.ecm.platform.query.api.PageProvider; 045import org.nuxeo.ecm.platform.query.api.PageProviderService; 046import org.nuxeo.ecm.platform.query.core.GenericPageProviderDescriptor; 047import org.nuxeo.ecm.platform.query.nxql.CoreQueryAndFetchPageProvider; 048import org.nuxeo.ecm.platform.query.nxql.CoreQueryDocumentPageProvider; 049 050/** 051 * Operation to execute a query or a named provider with support for Pagination 052 * 053 * @author Tiry (tdelprat@nuxeo.com) 054 * @since 5.7 055 */ 056@Operation(id = ResultSetPageProviderOperation.ID, category = Constants.CAT_FETCH, label = "QueryAndFetch", description = "Perform " 057 + "a query or a named provider query on the repository. Result is " 058 + "paginated. The result is returned as a RecordSet (QueryAndFetch) " 059 + "rather than as a List of Document" 060 + "The query result will become the input for the next " 061 + "operation. If no query or provider name is given, a query returning " 062 + "all the documents that the user has access to will be executed.", addToStudio = false, aliases = { "Resultset.PageProvider" }) 063public class ResultSetPageProviderOperation { 064 065 private static final Log log = LogFactory.getLog(ResultSetPageProviderOperation.class); 066 067 public static final String ID = "Repository.ResultSetPageProvider"; 068 069 public static final String CURRENT_USERID_PATTERN = "$currentUser"; 070 071 public static final String CURRENT_REPO_PATTERN = "$currentRepository"; 072 073 public static final String DESC = "DESC"; 074 075 public static final String ASC = "ASC"; 076 077 public static final String CMIS = "CMIS"; 078 079 @Context 080 protected OperationContext context; 081 082 @Context 083 protected CoreSession session; 084 085 @Context 086 protected PageProviderService ppService; 087 088 @Param(name = "providerName", required = false) 089 protected String providerName; 090 091 /** 092 * @deprecated since 6.0 use instead {@link org.nuxeo.ecm.automation .core.operations.services.query.ResultSetQuery} 093 */ 094 @Deprecated 095 @Param(name = "query", required = false) 096 protected String query; 097 098 @Param(name = "language", required = false, widget = Constants.W_OPTION, values = { NXQL.NXQL, CMIS }) 099 protected String lang = NXQL.NXQL; 100 101 @Param(name = "page", required = false) 102 protected Integer page; 103 104 @Param(name = "pageSize", required = false) 105 protected Integer pageSize; 106 107 /** 108 * @deprecated since 6.0 use instead {@link #sortBy and @link #sortOrder} 109 */ 110 @Deprecated 111 @Param(name = "sortInfo", required = false) 112 protected StringList sortInfoAsStringList; 113 114 @Param(name = "queryParams", required = false) 115 protected StringList strParameters; 116 117 @Param(name = "documentLinkBuilder", required = false) 118 protected String documentLinkBuilder; 119 120 /** 121 * @since 5.7 122 */ 123 @Param(name = "maxResults", required = false) 124 protected String maxResults = "100"; 125 126 /** 127 * @since 6.0 128 */ 129 @Param(name = PageProviderService.NAMED_PARAMETERS, required = false, description = "Named parameters to pass to the page provider to " 130 + "fill in query variables.") 131 protected Properties namedParameters; 132 133 /** 134 * @since 6.0 135 */ 136 @Param(name = "sortBy", required = false, description = "Sort by " + "properties (separated by comma)") 137 protected String sortBy; 138 139 /** 140 * @since 6.0 141 */ 142 @Param(name = "sortOrder", required = false, description = "Sort order, " + "ASC or DESC", widget = Constants.W_OPTION, values = { 143 ASC, DESC }) 144 protected String sortOrder; 145 146 @SuppressWarnings("unchecked") 147 @OperationMethod 148 public RecordSet run() throws OperationException { 149 150 List<SortInfo> sortInfos = null; 151 if (sortInfoAsStringList != null) { 152 sortInfos = new ArrayList<SortInfo>(); 153 for (String sortInfoDesc : sortInfoAsStringList) { 154 SortInfo sortInfo; 155 if (sortInfoDesc.contains("|")) { 156 String[] parts = sortInfoDesc.split("|"); 157 sortInfo = new SortInfo(parts[0], Boolean.parseBoolean(parts[1])); 158 } else { 159 sortInfo = new SortInfo(sortInfoDesc, true); 160 } 161 sortInfos.add(sortInfo); 162 } 163 } else { 164 // Sort Info Management 165 if (!StringUtils.isBlank(sortBy)) { 166 sortInfos = new ArrayList<>(); 167 String[] sorts = sortBy.split(","); 168 String[] orders = null; 169 if (!StringUtils.isBlank(sortOrder)) { 170 orders = sortOrder.split(","); 171 } 172 for (int i = 0; i < sorts.length; i++) { 173 String sort = sorts[i]; 174 boolean sortAscending = (orders != null && orders.length > i && "asc".equals(orders[i].toLowerCase())); 175 sortInfos.add(new SortInfo(sort, sortAscending)); 176 } 177 } 178 } 179 180 Object[] parameters = null; 181 182 if (strParameters != null && !strParameters.isEmpty()) { 183 parameters = strParameters.toArray(new String[strParameters.size()]); 184 // expand specific parameters 185 for (int idx = 0; idx < parameters.length; idx++) { 186 String value = (String) parameters[idx]; 187 if (value.equals(CURRENT_USERID_PATTERN)) { 188 parameters[idx] = session.getPrincipal().getName(); 189 } else if (value.equals(CURRENT_REPO_PATTERN)) { 190 parameters[idx] = session.getRepositoryName(); 191 } 192 } 193 } 194 195 Map<String, Serializable> props = new HashMap<String, Serializable>(); 196 props.put(CoreQueryDocumentPageProvider.CORE_SESSION_PROPERTY, (Serializable) session); 197 198 if (query == null && StringUtils.isEmpty(providerName)) { 199 // provide a defaut query 200 query = "SELECT * from Document"; 201 } 202 203 Long targetPage = null; 204 if (page != null) { 205 targetPage = page.longValue(); 206 } 207 Long targetPageSize = null; 208 if (pageSize != null) { 209 targetPageSize = pageSize.longValue(); 210 } 211 212 DocumentModel searchDocumentModel = DocumentPageProviderOperation.getSearchDocumentModel(session, ppService, 213 providerName, namedParameters); 214 215 final class QueryAndFetchProviderDescriptor extends GenericPageProviderDescriptor { 216 private static final long serialVersionUID = 1L; 217 218 public QueryAndFetchProviderDescriptor() { 219 super(); 220 try { 221 klass = (Class<PageProvider<?>>) Class.forName(CoreQueryAndFetchPageProvider.class.getName()); 222 } catch (ClassNotFoundException e) { 223 log.error(e, e); 224 } 225 } 226 } 227 228 PageProvider<Map<String, Serializable>> pp = null; 229 if (query != null) { 230 QueryAndFetchProviderDescriptor desc = new QueryAndFetchProviderDescriptor(); 231 desc.setPattern(query); 232 if (maxResults != null && !maxResults.isEmpty() && !maxResults.equals("-1")) { 233 // set the maxResults to avoid slowing down queries 234 desc.getProperties().put("maxResults", maxResults); 235 } 236 pp = (CoreQueryAndFetchPageProvider) ppService.getPageProvider("", desc, searchDocumentModel, sortInfos, 237 targetPageSize, targetPage, props, parameters); 238 } else { 239 pp = (PageProvider<Map<String, Serializable>>) ppService.getPageProvider(providerName, searchDocumentModel, 240 sortInfos, targetPageSize, targetPage, props, parameters); 241 } 242 PaginableRecordSetImpl res = new PaginableRecordSetImpl(pp); 243 if (res.hasError()) { 244 throw new OperationException(res.getErrorMessage()); 245 } 246 return res; 247 248 } 249}