001/* 002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * bstefanescu 011 */ 012package org.nuxeo.ecm.automation.core.operations.document; 013 014import java.util.HashSet; 015import java.util.Set; 016 017import org.apache.commons.logging.Log; 018import org.apache.commons.logging.LogFactory; 019import org.nuxeo.common.utils.StringUtils; 020import org.nuxeo.ecm.automation.OperationContext; 021import org.nuxeo.ecm.automation.core.Constants; 022import org.nuxeo.ecm.automation.core.annotations.Context; 023import org.nuxeo.ecm.automation.core.annotations.Operation; 024import org.nuxeo.ecm.automation.core.annotations.OperationMethod; 025import org.nuxeo.ecm.automation.core.annotations.Param; 026import org.nuxeo.ecm.automation.core.events.DocumentAttributeFilterFactory; 027import org.nuxeo.ecm.automation.core.scripting.Expression; 028import org.nuxeo.ecm.automation.core.scripting.Scripting; 029import org.nuxeo.ecm.core.api.DocumentModel; 030import org.nuxeo.ecm.core.api.DocumentModelList; 031import org.nuxeo.ecm.core.api.Filter; 032import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl; 033 034/** 035 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 036 */ 037@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.") 038public class FilterDocuments { 039 040 private static final Log log = LogFactory.getLog(FilterDocuments.class); 041 042 public static final String ID = "Document.Filter"; 043 044 @Context 045 protected OperationContext ctx; 046 047 @Param(name = "types", required = false) 048 protected String types; // comma separated list. 049 050 @Param(name = "facet", required = false) 051 protected String facet; 052 053 @Param(name = "lifecycle", required = false) 054 protected String lifeCycle; 055 056 @Param(name = "pathStartsWith", required = false) 057 protected String pathStartsWith; 058 059 @Param(name = "condition", required = false) 060 protected String condition; 061 062 @Param(name = "class", required = false, widget = Constants.W_OPTION, values = { 063 DocumentAttributeFilterFactory.ANY_DOC, DocumentAttributeFilterFactory.REGULAR_DOC, 064 DocumentAttributeFilterFactory.LINK_DOC, DocumentAttributeFilterFactory.PUBLISHED_DOC, 065 DocumentAttributeFilterFactory.PROXY_DOC, DocumentAttributeFilterFactory.VERSION_DOC, 066 DocumentAttributeFilterFactory.IMMUTABLE_DOC, DocumentAttributeFilterFactory.MUTABLE_DOC }) 067 protected String attr; 068 069 @OperationMethod 070 public DocumentModelList run(DocumentModelList docs) { 071 Condition cond = new Condition(); 072 DocumentModelList result = new DocumentModelListImpl(); 073 for (DocumentModel doc : docs) { 074 if (cond.accept(doc)) { 075 result.add(doc); 076 } 077 } 078 return result; 079 } 080 081 protected class Condition implements Filter { 082 private static final long serialVersionUID = 1L; 083 084 Set<String> types; 085 086 String facet; 087 088 String lc; 089 090 String path; 091 092 Expression expr; 093 094 Filter attr; 095 096 Condition() { 097 String v = FilterDocuments.this.types; 098 if (v != null) { 099 v = v.trim(); 100 if (v.length() > 0) { 101 types = new HashSet<String>(); 102 for (String t : StringUtils.split(v, ',', true)) { 103 types.add(t); 104 } 105 } 106 } 107 v = FilterDocuments.this.facet; 108 if (v != null) { 109 v = v.trim(); 110 if (v.length() > 0) { 111 facet = v; 112 } 113 } 114 v = lifeCycle; 115 if (v != null) { 116 v = v.trim(); 117 if (v.length() > 0) { 118 lc = v; 119 } 120 } 121 v = pathStartsWith; 122 if (v != null) { 123 v = v.trim(); 124 if (v.length() > 0) { 125 path = v; 126 } 127 } 128 v = condition; 129 if (v != null) { 130 v = v.trim(); 131 if (v.length() > 0) { 132 expr = Scripting.newExpression(v); 133 } 134 } 135 v = FilterDocuments.this.attr; 136 if (v != null) { 137 attr = DocumentAttributeFilterFactory.getFilter(v); 138 } 139 } 140 141 @Override 142 public boolean accept(DocumentModel doc) { 143 if (types != null) { 144 if (!types.contains(doc.getType())) { 145 return false; 146 } 147 } 148 if (facet != null) { 149 if (!doc.getFacets().contains(facet)) { 150 return false; 151 } 152 } 153 if (lc != null) { 154 if (!lc.equals(doc.getCurrentLifeCycleState())) { 155 return false; 156 } 157 } 158 if (path != null) { 159 if (!doc.getPathAsString().startsWith(path)) { 160 return false; 161 } 162 } 163 if (attr != null) { 164 if (!attr.accept(doc)) { 165 return false; 166 } 167 } 168 if (expr != null) { 169 try { 170 if (!(Boolean) expr.eval(ctx)) { 171 return false; 172 } 173 } catch (RuntimeException e) { 174 log.error(e, e); 175 } 176 } 177 return true; 178 } 179 } 180 181}