/*
* ====================
* 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;
import static java.util.Collections.unmodifiableSet;
import static org.identityconnectors.common.CollectionUtil.newCaseInsensitiveMap;
import static org.identityconnectors.common.CollectionUtil.newCaseInsensitiveSet;
import static org.identityconnectors.ldap.LdapUtil.quietCreateLdapName;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.Set;
import javax.naming.InvalidNameException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.LdapName;
import org.identityconnectors.framework.common.exceptions.ConnectorException;
public abstract class LdapEntry {
public static final Set<String> ENTRY_DN_ATTRS;
static {
Set<String> set = newCaseInsensitiveSet();
set.add("entryDN");
// These two are used throughout the adapter.
set.add("dn");
set.add("distinguishedName");
ENTRY_DN_ATTRS = unmodifiableSet(set);
}
public static LdapEntry create(String baseDN, SearchResult result) {
return new SearchResultBased(baseDN, result);
}
public static LdapEntry create(String entryDN, Attributes attributes) {
return new Simple(entryDN, attributes);
}
public static boolean isDNAttribute(String attrID) {
return ENTRY_DN_ATTRS.contains(attrID);
}
public abstract Attributes getAttributes();
public abstract LdapName getDN();
private static LdapName join(String name, String baseDN) {
LdapName result = quietCreateLdapName(cleanNameToParse(name));
if (baseDN != null) {
LdapName contextName = quietCreateLdapName(baseDN);
try {
result.addAll(0, contextName);
} catch (InvalidNameException e) {
throw new ConnectorException(e);
}
}
return result;
}
// Copied from adapter, but not clear why it is needed.
private static String cleanNameToParse(String name) {
String nameToParse = name;
// Remove any extra leading double quote.
if (nameToParse.startsWith("\"")) {
nameToParse = nameToParse.substring(1, nameToParse.length());
}
// Remove any extra trailing double quote.
if (nameToParse.endsWith("\"")) {
nameToParse = nameToParse.substring(0, nameToParse.length() - 1);
}
return nameToParse;
}
private static final class SearchResultBased extends LdapEntry {
private final String baseDN;
private final SearchResult result;
private Attributes attributes;
private LdapName dn;
public SearchResultBased(String baseDN, SearchResult result) {
assert result != null;
this.baseDN = baseDN;
this.result = result;
}
@Override
public Attributes getAttributes() {
if (attributes == null) {
attributes = new DNAttributes(this, result.getAttributes());
}
return attributes;
}
@Override
public LdapName getDN() {
if (dn == null) {
if (result.isRelative()) {
try {
//dn = join(result.getName(), baseDN);
dn = new LdapName(result.getNameInNamespace());
} catch (InvalidNameException ex) {
throw new ConnectorException(ex);
}
} else {
// Striping the scheme and host, according to a comment in the adapter.
dn = join(getDNFromLdapUrl(result.getName()), null);
}
}
return dn;
}
private String getDNFromLdapUrl(String url) {
int schemeEndPos = url.indexOf("://");
if (schemeEndPos < 0) {
return null;
}
int slashAfterHostPos = url.indexOf('/', schemeEndPos + 3);
if (slashAfterHostPos < 0) {
return null;
}
try {
return java.net.URLDecoder.decode(url.substring(slashAfterHostPos + 1), "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
private static final class Simple extends LdapEntry {
private final String entryDN;
private final Attributes attributes;
private LdapName dn;
public Simple(String entryDN, Attributes attributes) {
assert entryDN != null;
assert attributes != null;
this.entryDN = entryDN;
this.attributes = new DNAttributes(this, attributes);
}
@Override
public Attributes getAttributes() {
return attributes;
}
@Override
public LdapName getDN() {
if (dn == null) {
dn = join(entryDN, null);
}
return dn;
}
}
private final static class DNAttributes extends AppendingAttributes {
private static final long serialVersionUID = 1L;
private final LdapEntry ldapEntry;
private final Map<String, Attribute> dnAttributes = newCaseInsensitiveMap();
public DNAttributes(LdapEntry ldapEntry, Attributes delegate) {
super(delegate);
this.ldapEntry = ldapEntry;
}
@Override
public Object clone() {
return new DNAttributes(ldapEntry, (Attributes) delegate.clone());
}
@Override
protected Attribute getAttributeToAppend(String attrID) {
if (ENTRY_DN_ATTRS.contains(attrID)) {
Attribute result = dnAttributes.get(attrID);
if (result == null) {
result = new BasicAttribute(attrID, ldapEntry.getDN().toString());
dnAttributes.put(attrID, result);
}
return result;
}
return null;
}
@Override
protected Set<String> getAttributeIDsToAppend() {
return ENTRY_DN_ATTRS;
}
}
}