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 * bstefanescu 018 */ 019package org.nuxeo.ecm.automation.core.operations.document; 020 021import java.util.HashSet; 022import java.util.Set; 023 024import org.apache.commons.logging.Log; 025import org.apache.commons.logging.LogFactory; 026import org.nuxeo.common.utils.StringUtils; 027import org.nuxeo.ecm.automation.OperationContext; 028import org.nuxeo.ecm.automation.core.Constants; 029import org.nuxeo.ecm.automation.core.annotations.Context; 030import org.nuxeo.ecm.automation.core.annotations.Operation; 031import org.nuxeo.ecm.automation.core.annotations.OperationMethod; 032import org.nuxeo.ecm.automation.core.annotations.Param; 033import org.nuxeo.ecm.automation.core.collectors.DocumentModelListCollector; 034import org.nuxeo.ecm.automation.core.events.DocumentAttributeFilterFactory; 035import org.nuxeo.ecm.automation.core.scripting.Expression; 036import org.nuxeo.ecm.automation.core.scripting.Scripting; 037import org.nuxeo.ecm.core.api.DocumentModel; 038import org.nuxeo.ecm.core.api.DocumentModelList; 039import org.nuxeo.ecm.core.api.Filter; 040import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl; 041 042/** 043 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 044 */ 045@Operation(id = FilterDocuments.ID, category = Constants.CAT_DOCUMENT, label = "Filter List", description = "Filter the input list of documents given a condition. The condition can be expressed using 4 parameters: types, facets, lifecycle and condition. If more than one parameter is specified an AND will be used to group conditions. <br>The 'types' parameter can take a comma separated list of document type: File,Note.<br>The 'facet' parameter can take a single facet name.<br> The 'life cycle' parameter takes a name of a life cycle state the document should have.<br>The 'condition' parameter can take any EL expression.<p>Returns the list of documents that match the filter condition.") 046public class FilterDocuments { 047 048 private static final Log log = LogFactory.getLog(FilterDocuments.class); 049 050 public static final String ID = "Document.Filter"; 051 052 @Context 053 protected OperationContext ctx; 054 055 @Param(name = "types", required = false) 056 protected String types; // comma separated list. 057 058 @Param(name = "facet", required = false) 059 protected String facet; 060 061 @Param(name = "lifecycle", required = false) 062 protected String lifeCycle; 063 064 @Param(name = "pathStartsWith", required = false) 065 protected String pathStartsWith; 066 067 @Param(name = "condition", required = false) 068 protected String condition; 069 070 @Param(name = "class", required = false, widget = Constants.W_OPTION, values = { 071 DocumentAttributeFilterFactory.ANY_DOC, DocumentAttributeFilterFactory.REGULAR_DOC, 072 DocumentAttributeFilterFactory.LINK_DOC, DocumentAttributeFilterFactory.PUBLISHED_DOC, 073 DocumentAttributeFilterFactory.PROXY_DOC, DocumentAttributeFilterFactory.VERSION_DOC, 074 DocumentAttributeFilterFactory.IMMUTABLE_DOC, DocumentAttributeFilterFactory.MUTABLE_DOC }) 075 protected String attr; 076 077 @OperationMethod(collector = DocumentModelListCollector.class) 078 public DocumentModelList run(DocumentModel doc) { 079 // Method rewritten to use Collector in order to execute condition on each document 080 Condition cond = new Condition(); 081 DocumentModelList ret = new DocumentModelListImpl(); 082 if (cond.accept(doc)) { 083 ret.add(doc); 084 } 085 return ret; 086 } 087 088 protected class Condition implements Filter { 089 090 Set<String> types; 091 092 String facet; 093 094 String lc; 095 096 String path; 097 098 Expression expr; 099 100 Filter attr; 101 102 Condition() { 103 String v = FilterDocuments.this.types; 104 if (v != null) { 105 v = v.trim(); 106 if (v.length() > 0) { 107 types = new HashSet<>(); 108 for (String t : StringUtils.split(v, ',', true)) { 109 types.add(t); 110 } 111 } 112 } 113 v = FilterDocuments.this.facet; 114 if (v != null) { 115 v = v.trim(); 116 if (v.length() > 0) { 117 facet = v; 118 } 119 } 120 v = lifeCycle; 121 if (v != null) { 122 v = v.trim(); 123 if (v.length() > 0) { 124 lc = v; 125 } 126 } 127 v = pathStartsWith; 128 if (v != null) { 129 v = v.trim(); 130 if (v.length() > 0) { 131 path = v; 132 } 133 } 134 v = condition; 135 if (v != null) { 136 v = v.trim(); 137 if (v.length() > 0) { 138 expr = Scripting.newExpression(v); 139 } 140 } 141 v = FilterDocuments.this.attr; 142 if (v != null) { 143 attr = DocumentAttributeFilterFactory.getFilter(v); 144 } 145 } 146 147 @Override 148 public boolean accept(DocumentModel doc) { 149 if (types != null) { 150 if (!types.contains(doc.getType())) { 151 return false; 152 } 153 } 154 if (facet != null) { 155 if (!doc.getFacets().contains(facet)) { 156 return false; 157 } 158 } 159 if (lc != null) { 160 if (!lc.equals(doc.getCurrentLifeCycleState())) { 161 return false; 162 } 163 } 164 if (path != null) { 165 if (!doc.getPathAsString().startsWith(path)) { 166 return false; 167 } 168 } 169 if (attr != null) { 170 if (!attr.accept(doc)) { 171 return false; 172 } 173 } 174 if (expr != null) { 175 try { 176 if (!(Boolean) expr.eval(ctx)) { 177 return false; 178 } 179 } catch (RuntimeException e) { 180 log.error(e, e); 181 } 182 } 183 return true; 184 } 185 } 186 187}