/* | 
|
 * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. | 
|
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
|
 * | 
|
 * This code is free software; you can redistribute it and/or modify it | 
|
 * under the terms of the GNU General Public License version 2 only, as | 
|
 * published by the Free Software Foundation.  Oracle designates this | 
|
 * particular file as subject to the "Classpath" exception as provided | 
|
 * by Oracle in the LICENSE file that accompanied this code. | 
|
 * | 
|
 * This code is distributed in the hope that it will be useful, but WITHOUT | 
|
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
|
 * version 2 for more details (a copy is included in the LICENSE file that | 
|
 * accompanied this code). | 
|
 * | 
|
 * You should have received a copy of the GNU General Public License version | 
|
 * 2 along with this work; if not, write to the Free Software Foundation, | 
|
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
|
 * | 
|
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 
|
 * or visit www.oracle.com if you need additional information or have any | 
|
 * questions. | 
|
*/  | 
|
package com.sun.jndi.ldap;  | 
|
import java.io.IOException;  | 
|
import java.util.Hashtable;  | 
|
import java.util.Vector;  | 
|
import javax.naming.*;  | 
|
import javax.naming.directory.*;  | 
|
/** | 
|
  * This subclass is used by LDAP to implement the schema calls. | 
|
  * Basically, it keeps track of which context it is an attribute of | 
|
  * so it can get the schema for that cotnext. | 
|
  * | 
|
  * @author Jon Ruiz | 
|
*/  | 
|
final class LdapAttribute extends BasicAttribute {  | 
|
static final long serialVersionUID = -4288716561020779584L;  | 
|
private transient DirContext baseCtx = null;  | 
|
private Name rdn = new CompositeName();  | 
|
// these two are used to reconstruct the baseCtx if this attribute has  | 
|
    // been serialized ( | 
|
private String baseCtxURL;  | 
|
private Hashtable<String, ? super String> baseCtxEnv;  | 
|
@SuppressWarnings("unchecked") // clone()  | 
|
public Object clone() {  | 
|
LdapAttribute attr = new LdapAttribute(this.attrID, baseCtx, rdn);  | 
|
attr.values = (Vector<Object>)values.clone();  | 
|
return attr;  | 
|
}  | 
|
    /** | 
|
      * Adds a new value to this attribute. | 
|
      * | 
|
      * @param attrVal The value to be added. If null, a null value is added to | 
|
      *                the attribute. | 
|
      * @return true Always returns true. | 
|
*/  | 
|
public boolean add(Object attrVal) {  | 
|
// LDAP attributes don't contain duplicate values so there's no need  | 
|
        // to check if the value already exists before adding it. | 
|
values.addElement(attrVal);  | 
|
return true;  | 
|
}  | 
|
    /** | 
|
      * Constructs a new instance of an attribute. | 
|
      * | 
|
      * @param id The attribute's id. It cannot be null. | 
|
*/  | 
|
LdapAttribute(String id) {  | 
|
super(id);  | 
|
}  | 
|
    /** | 
|
      * Constructs a new instance of an attribute. | 
|
      * | 
|
      * @param id The attribute's id. It cannot be null. | 
|
      * @param baseCtx  the baseCtx object of this attribute | 
|
      * @param rdn      the RDN of the entry (relative to baseCtx) | 
|
*/  | 
|
private LdapAttribute(String id, DirContext baseCtx, Name rdn) {  | 
|
super(id);  | 
|
this.baseCtx = baseCtx;  | 
|
this.rdn = rdn;  | 
|
}  | 
|
     /** | 
|
      * Sets the baseCtx and rdn used to find the attribute's schema | 
|
      * Used by LdapCtx.setParents(). | 
|
*/  | 
|
void setParent(DirContext baseCtx, Name rdn) {  | 
|
this.baseCtx = baseCtx;  | 
|
this.rdn = rdn;  | 
|
}  | 
|
    /** | 
|
     * returns the ctx this attribute came from. This call allows | 
|
     * LDAPAttribute to be serializable. 'baseCtx' is transient so if | 
|
     * it is null, the `baseCtxURL` is used to reconstruct the context | 
|
     * to which calls are made. | 
|
*/  | 
|
private DirContext getBaseCtx() throws NamingException {  | 
|
if(baseCtx == null) {  | 
|
if (baseCtxEnv == null) {  | 
|
baseCtxEnv = new Hashtable<String, String>(3);  | 
|
}  | 
|
baseCtxEnv.put(Context.INITIAL_CONTEXT_FACTORY,  | 
|
                             "com.sun.jndi.ldap.LdapCtxFactory"); | 
|
baseCtxEnv.put(Context.PROVIDER_URL,baseCtxURL);  | 
|
baseCtx = (new InitialDirContext(baseCtxEnv));  | 
|
}  | 
|
return baseCtx;  | 
|
}  | 
|
    /** | 
|
     * This is called when the object is serialized. It is | 
|
     * overridden so that the appropriate class variables can be set | 
|
     * to re-construct the baseCtx when deserialized. Setting these | 
|
     * variables is costly, so it is only done if the object | 
|
     * is actually serialized. | 
|
*/  | 
|
private void writeObject(java.io.ObjectOutputStream out)  | 
|
throws IOException {  | 
|
        // setup internal state | 
|
this.setBaseCtxInfo();  | 
|
        // let the ObjectOutpurStream do the real work of serialization | 
|
out.defaultWriteObject();  | 
|
}  | 
|
    /** | 
|
     * sets the information needed to reconstruct the baseCtx if | 
|
     * we are serialized. This must be called _before_ the object is | 
|
     * serialized!!! | 
|
*/  | 
|
@SuppressWarnings("unchecked") // clone()  | 
|
    private void setBaseCtxInfo() { | 
|
Hashtable<String, Object> realEnv = null;  | 
|
Hashtable<String, Object> secureEnv = null;  | 
|
if (baseCtx != null) {  | 
|
realEnv = ((LdapCtx)baseCtx).envprops;  | 
|
this.baseCtxURL = ((LdapCtx)baseCtx).getURL();  | 
|
}  | 
|
if(realEnv != null && realEnv.size() > 0 ) {  | 
|
// remove any security credentials - otherwise the serialized form  | 
|
            // would store them in the clear | 
|
for (String key : realEnv.keySet()){  | 
|
                if (key.indexOf("security") != -1 ) { | 
|
//if we need to remove props, we must do it to a clone  | 
|
//of the environment. cloning is expensive, so we only do  | 
|
                    //it if we have to. | 
|
if(secureEnv == null) {  | 
|
secureEnv = (Hashtable<String, Object>)realEnv.clone();  | 
|
}  | 
|
secureEnv.remove(key);  | 
|
}  | 
|
}  | 
|
}  | 
|
        // set baseCtxEnv depending on whether we removed props or not | 
|
this.baseCtxEnv = (secureEnv == null ? realEnv : secureEnv);  | 
|
}  | 
|
    /** | 
|
      * Retrieves the syntax definition associated with this attribute. | 
|
      * @return This attribute's syntax definition. | 
|
*/  | 
|
public DirContext getAttributeSyntaxDefinition() throws NamingException {  | 
|
        // get the syntax id from the attribute def | 
|
DirContext schema = getBaseCtx().getSchema(rdn);  | 
|
DirContext attrDef = (DirContext)schema.lookup(  | 
|
LdapSchemaParser.ATTRIBUTE_DEFINITION_NAME + "/" + getID());  | 
|
Attribute syntaxAttr = attrDef.getAttributes("").get("SYNTAX");  | 
|
if(syntaxAttr == null || syntaxAttr.size() == 0) {  | 
|
throw new NameNotFoundException(  | 
|
getID() + "does not have a syntax associated with it");  | 
|
}  | 
|
String syntaxName = (String)syntaxAttr.get();  | 
|
        // look in the schema tree for the syntax definition | 
|
return (DirContext)schema.lookup(  | 
|
LdapSchemaParser.SYNTAX_DEFINITION_NAME + "/" + syntaxName);  | 
|
}  | 
|
    /** | 
|
      * Retrieves this attribute's schema definition. | 
|
      * | 
|
      * @return This attribute's schema definition. | 
|
*/  | 
|
public DirContext getAttributeDefinition() throws NamingException {  | 
|
DirContext schema = getBaseCtx().getSchema(rdn);  | 
|
return (DirContext)schema.lookup(  | 
|
LdapSchemaParser.ATTRIBUTE_DEFINITION_NAME + "/" + getID());  | 
|
}  | 
|
}  |