/* * ==================== * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of the Common Development * and Distribution License("CDDL") (the "License"). You may not use this file * except in compliance with the License. * * You can obtain a copy of the License at * http://IdentityConnectors.dev.java.net/legal/license.txt * See the License for the specific language governing permissions and limitations * under the License. * * When distributing the Covered Code, include this CDDL Header Notice in each file * and include the License file at identityconnectors/legal/license.txt. * If applicable, add the following below this CDDL Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== */ package org.identityconnectors.ldap.search; import org.identityconnectors.framework.common.objects.Name; import org.identityconnectors.framework.common.objects.filter.EqualsFilter; /** * Encapsulates an LDAP filter. An instance of this class is consists of * an optional entry DN and an optional native LDAP filter. The semantics of * such an instance is "an LDAP entry with this entry DN (if specified) and * matching this native filter (if specified)". * * <p>The problem this class solves is the following. * When an attribute, for instance {@link Name}, is mapped to an entry's DN, * and the user constructs an {@link EqualsFilter} for that attribute, the connector * needs to translate that <code>Filter</code> into a native LDAP filter. The connector * could use the <code>entryDN</code> attribute in the native filter, but some servers might * not support that attribute. Instead, such a <code>Filter</code> is translated * to an <code>LdapFilter</code> with that entry DN. A composed filter, for instance:</p> * * <pre> * Name name = new Name("uid=foo,dc=example,dc=com"); * Attribute attr = AttributeBuilder.build("foo", "bar"); * FilterBuilder.and( * FilterBuilder.equalTo(name), * FilterBuilder.equalTo(attr)); * </pre> * * <p>can be translated to a single <code>LdapFilter</code> whose entry DN corresponds * to <code>aName</code> and whose filter string is <code>(foo=bar)</code>.</p> */ public final class LdapFilter { private final String nativeFilter; private final String entryDN; public static LdapFilter forEntryDN(String entryDN) { return new LdapFilter(null, entryDN); } public static LdapFilter forNativeFilter(String nativeFilter) { return new LdapFilter(nativeFilter, null); } private LdapFilter(String nativeFilter, String entryDN) { this.nativeFilter = nativeFilter; this.entryDN = entryDN; } public LdapFilter withNativeFilter(String nativeFilter) { return new LdapFilter(nativeFilter, this.entryDN); } public String getNativeFilter() { return nativeFilter; } public String getEntryDN() { return entryDN; } /** * Logically "ANDs" together this filter with another filter. * * <p>If at most one of the two filters has an entry DN, the * result is a filter with that entry DN (if any) and a native filter * whose value is the native filters of the two filters "ANDed" * together using the LDAP <code>&</code> operator.</p> * * <p>Otherwise, the method returns <code>null</code>. * * @param other the other filter. * * @return the two filters "ANDed" together or <code>null</code>. */ public LdapFilter and(LdapFilter other) { if (entryDN == null || other.entryDN == null) { return new LdapFilter( combine(nativeFilter, other.nativeFilter, '&'), entryDN != null ? entryDN : other.entryDN); } return null; } /** * Logically "ORs" together this filter with another filter. * * <p>If none of the two filters has an entry DN, the * result is a filter with no entry DN and a native filter * whose value is the native filters of the two filters "ORed" * together using the LDAP <code>|</code> filter operator.</p> * * <p>Otherwise, the method returns <code>null</code>. * * @param other the other filter. * * @return the two filters "ORed" together or <code>null</code>. */ public LdapFilter or(LdapFilter other) { if (entryDN == null && other.entryDN == null) { return new LdapFilter( combine(nativeFilter, other.nativeFilter, '|'), null); } return null; } private static String combine(String left, String right, char op) { if (left != null) { if (right != null) { StringBuilder builder = new StringBuilder(); builder.append('('); builder.append(op); builder.append(left); builder.append(right); builder.append(')'); return builder.toString(); } else { return left; } } else { return right; } } @Override public boolean equals(Object o) { if (o instanceof LdapFilter) { LdapFilter that = (LdapFilter)o; if ((nativeFilter == null) ? (that.nativeFilter != null) : !nativeFilter.equals(that.nativeFilter)) { return false; } if ((entryDN == null) ? (that.entryDN != null) : !entryDN.equals(that.entryDN)) { return false; } return true; } return false; } @Override public int hashCode() { return (nativeFilter != null ? nativeFilter.hashCode() : 0) ^ (entryDN != null ? entryDN.hashCode() : 0); } @Override public String toString() { return "LdapFilter[nativeFilter: " + nativeFilter + "; entryDN: " + entryDN + "]"; } }