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 * Georges Racinet 011 * Florent Guillaume 012 */ 013 014package org.nuxeo.ecm.core.api.impl; 015 016import java.util.Collection; 017import java.util.Collections; 018import java.util.HashSet; 019import java.util.List; 020import java.util.Set; 021 022import org.nuxeo.ecm.core.api.DocumentModel; 023import org.nuxeo.ecm.core.api.Filter; 024 025/** 026 * A filter based on facets. 027 * 028 * @author Georges Racinet 029 * @author Florent Guillaume 030 */ 031public class FacetFilter implements Filter { 032 033 private static final long serialVersionUID = 1L; 034 035 public static final FacetFilter ALLOW = new FacetFilter((List<String>) null, (List<String>) null); 036 037 /** Set of required facets. Never {@code null}. */ 038 public final Set<String> required; 039 040 /** Set of excluded facets. Never {@code null}. */ 041 public final Set<String> excluded; 042 043 public final Boolean shortcut; 044 045 /** 046 * Generic constructor. 047 * 048 * @param required list of facets the models must have to pass the filter 049 * @param excluded list of facets the models must not have to pass the filter 050 */ 051 public FacetFilter(List<String> required, List<String> excluded) { 052 if (required == null) { 053 this.required = Collections.emptySet(); 054 } else { 055 this.required = new HashSet<String>(required); 056 } 057 if (excluded == null) { 058 this.excluded = Collections.emptySet(); 059 } else { 060 this.excluded = new HashSet<String>(excluded); 061 } 062 shortcut = findShortcut(); 063 } 064 065 /** 066 * Simpler constructor to filter on a single facet. 067 * 068 * @param facet the facet to filter on 069 * @param isRequired if true, accepted models must have the facet; if false, accepted models must not have the facet 070 */ 071 public FacetFilter(String facet, boolean isRequired) { 072 if (isRequired) { 073 required = Collections.singleton(facet); 074 excluded = Collections.emptySet(); 075 } else { 076 required = Collections.emptySet(); 077 excluded = Collections.singleton(facet); 078 } 079 shortcut = null; 080 } 081 082 /** 083 * Constructor that ANDs two filters. 084 * 085 * @param filter1 the first filter 086 * @param filter2 the second filter 087 */ 088 public FacetFilter(FacetFilter filter1, FacetFilter filter2) { 089 if (filter1.required.isEmpty() && filter2.required.isEmpty()) { 090 required = Collections.emptySet(); 091 } else { 092 required = new HashSet<String>(filter1.required); 093 required.addAll(filter2.required); 094 } 095 if (filter1.excluded.isEmpty() && filter2.excluded.isEmpty()) { 096 excluded = Collections.emptySet(); 097 } else { 098 excluded = new HashSet<String>(filter1.excluded); 099 excluded.addAll(filter2.excluded); 100 } 101 shortcut = findShortcut(); 102 } 103 104 protected Boolean findShortcut() { 105 if (required.isEmpty() && excluded.isEmpty()) { 106 // no condition, always matches 107 return Boolean.TRUE; 108 } 109 Collection<String> intersection = new HashSet<String>(required); 110 intersection.retainAll(excluded); 111 if (!intersection.isEmpty()) { 112 // non-empty intersection, filter can never match 113 return Boolean.FALSE; 114 } 115 return null; 116 } 117 118 @Override 119 public boolean accept(DocumentModel docModel) { 120 if (shortcut != null) { 121 return shortcut; 122 } 123 for (String exc : excluded) { 124 if (docModel.hasFacet(exc)) { 125 return false; 126 } 127 } 128 for (String req : required) { 129 if (!docModel.hasFacet(req)) { 130 return false; 131 } 132 } 133 return true; 134 } 135 136}