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