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 private static final long serialVersionUID = 1L; 090 091 Set<String> types; 092 093 String facet; 094 095 String lc; 096 097 String path; 098 099 Expression expr; 100 101 Filter attr; 102 103 Condition() { 104 String v = FilterDocuments.this.types; 105 if (v != null) { 106 v = v.trim(); 107 if (v.length() > 0) { 108 types = new HashSet<String>(); 109 for (String t : StringUtils.split(v, ',', true)) { 110 types.add(t); 111 } 112 } 113 } 114 v = FilterDocuments.this.facet; 115 if (v != null) { 116 v = v.trim(); 117 if (v.length() > 0) { 118 facet = v; 119 } 120 } 121 v = lifeCycle; 122 if (v != null) { 123 v = v.trim(); 124 if (v.length() > 0) { 125 lc = v; 126 } 127 } 128 v = pathStartsWith; 129 if (v != null) { 130 v = v.trim(); 131 if (v.length() > 0) { 132 path = v; 133 } 134 } 135 v = condition; 136 if (v != null) { 137 v = v.trim(); 138 if (v.length() > 0) { 139 expr = Scripting.newExpression(v); 140 } 141 } 142 v = FilterDocuments.this.attr; 143 if (v != null) { 144 attr = DocumentAttributeFilterFactory.getFilter(v); 145 } 146 } 147 148 @Override 149 public boolean accept(DocumentModel doc) { 150 if (types != null) { 151 if (!types.contains(doc.getType())) { 152 return false; 153 } 154 } 155 if (facet != null) { 156 if (!doc.getFacets().contains(facet)) { 157 return false; 158 } 159 } 160 if (lc != null) { 161 if (!lc.equals(doc.getCurrentLifeCycleState())) { 162 return false; 163 } 164 } 165 if (path != null) { 166 if (!doc.getPathAsString().startsWith(path)) { 167 return false; 168 } 169 } 170 if (attr != null) { 171 if (!attr.accept(doc)) { 172 return false; 173 } 174 } 175 if (expr != null) { 176 try { 177 if (!(Boolean) expr.eval(ctx)) { 178 return false; 179 } 180 } catch (RuntimeException e) { 181 log.error(e, e); 182 } 183 } 184 return true; 185 } 186 } 187 188}