001: /*
002: * Copyright 1999-2002 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.jndi.ldap;
027:
028: import java.io.IOException;
029: import java.io.Serializable;
030: import java.util.Enumeration;
031: import java.util.Hashtable;
032: import java.util.Vector;
033: import javax.naming.*;
034: import javax.naming.directory.*;
035:
036: /**
037: * This subclass is used by LDAP to implement the schema calls.
038: * Basically, it keeps track of which context it is an attribute of
039: * so it can get the schema for that cotnext.
040: *
041: * @author Jon Ruiz
042: */
043: final class LdapAttribute extends BasicAttribute {
044:
045: static final long serialVersionUID = -4288716561020779584L;
046:
047: private transient DirContext baseCtx = null;
048: private Name rdn = new CompositeName();
049:
050: // these two are used to reconstruct the baseCtx if this attribute has
051: // been serialized (
052: private String baseCtxURL;
053: private Hashtable baseCtxEnv;
054:
055: public Object clone() {
056: LdapAttribute attr = new LdapAttribute(this .attrID, baseCtx,
057: rdn);
058: attr.values = (Vector) values.clone();
059: return attr;
060: }
061:
062: /**
063: * Adds a new value to this attribute.
064: *
065: * @param attrVal The value to be added. If null, a null value is added to
066: * the attribute.
067: * @return true Always returns true.
068: */
069: public boolean add(Object attrVal) {
070: // LDAP attributes don't contain duplicate values so there's no need
071: // to check if the value already exists before adding it.
072: values.addElement(attrVal);
073: return true;
074: }
075:
076: /**
077: * Constructs a new instance of an attribute.
078: *
079: * @param id The attribute's id. It cannot be null.
080: */
081: LdapAttribute(String id) {
082: super (id);
083: }
084:
085: /**
086: * Constructs a new instance of an attribute.
087: *
088: * @param id The attribute's id. It cannot be null.
089: * @param baseCtx the baseCtx object of this attribute
090: * @param rdn the RDN of the entry (relative to baseCtx)
091: */
092: private LdapAttribute(String id, DirContext baseCtx, Name rdn) {
093: super (id);
094: this .baseCtx = baseCtx;
095: this .rdn = rdn;
096: }
097:
098: /**
099: * Sets the baseCtx and rdn used to find the attribute's schema
100: * Used by LdapCtx.setParents().
101: */
102: void setParent(DirContext baseCtx, Name rdn) {
103: this .baseCtx = baseCtx;
104: this .rdn = rdn;
105: }
106:
107: /**
108: * returns the ctx this attribute came from. This call allows
109: * LDAPAttribute to be serializable. 'baseCtx' is transient so if
110: * it is null, the `baseCtxURL` is used to reconstruct the context
111: * to which calls are made.
112: */
113: private DirContext getBaseCtx() throws NamingException {
114: if (baseCtx == null) {
115: if (baseCtxEnv == null) {
116: baseCtxEnv = new Hashtable(3);
117: }
118: baseCtxEnv.put(Context.INITIAL_CONTEXT_FACTORY,
119: "com.sun.jndi.ldap.LdapCtxFactory");
120: baseCtxEnv.put(Context.PROVIDER_URL, baseCtxURL);
121: baseCtx = (new InitialDirContext(baseCtxEnv));
122: }
123: return baseCtx;
124: }
125:
126: /**
127: * This is called when the object is serialized. It is
128: * overridden so that the appropriate class variables can be set
129: * to re-construct the baseCtx when deserialized. Setting these
130: * variables is costly, so it is only done if the object
131: * is actually serialized.
132: */
133: private void writeObject(java.io.ObjectOutputStream out)
134: throws IOException {
135:
136: // setup internal state
137: this .setBaseCtxInfo();
138:
139: // let the ObjectOutpurStream do the real work of serialization
140: out.defaultWriteObject();
141: }
142:
143: /**
144: * sets the information needed to reconstruct the baseCtx if
145: * we are serialized. This must be called _before_ the object is
146: * serialized!!!
147: */
148: private void setBaseCtxInfo() {
149: Hashtable realEnv = null;
150: Hashtable secureEnv = null;
151:
152: if (baseCtx != null) {
153: realEnv = ((LdapCtx) baseCtx).envprops;
154: this .baseCtxURL = ((LdapCtx) baseCtx).getURL();
155: }
156:
157: if (realEnv != null && realEnv.size() > 0) {
158: // remove any security credentials - otherwise the serialized form
159: // would store them in the clear
160: Enumeration keys = realEnv.keys();
161: while (keys.hasMoreElements()) {
162: String key = (String) keys.nextElement();
163: if (key.indexOf("security") != -1) {
164:
165: //if we need to remove props, we must do it to a clone
166: //of the environment. cloning is expensive, so we only do
167: //it if we have to.
168: if (secureEnv == null) {
169: secureEnv = (Hashtable) realEnv.clone();
170: }
171: secureEnv.remove(key);
172: }
173: }
174: }
175:
176: // set baseCtxEnv depending on whether we removed props or not
177: this .baseCtxEnv = (secureEnv == null ? realEnv : secureEnv);
178: }
179:
180: /**
181: * Retrieves the syntax definition associated with this attribute.
182: * @return This attribute's syntax definition.
183: */
184: public DirContext getAttributeSyntaxDefinition()
185: throws NamingException {
186: // get the syntax id from the attribute def
187: DirContext schema = getBaseCtx().getSchema(rdn);
188: DirContext attrDef = (DirContext) schema
189: .lookup(LdapSchemaParser.ATTRIBUTE_DEFINITION_NAME
190: + "/" + getID());
191:
192: Attribute syntaxAttr = attrDef.getAttributes("").get("SYNTAX");
193:
194: if (syntaxAttr == null || syntaxAttr.size() == 0) {
195: throw new NameNotFoundException(getID()
196: + "does not have a syntax associated with it");
197: }
198:
199: String syntaxName = (String) syntaxAttr.get();
200:
201: // look in the schema tree for the syntax definition
202: return (DirContext) schema
203: .lookup(LdapSchemaParser.SYNTAX_DEFINITION_NAME + "/"
204: + syntaxName);
205: }
206:
207: /**
208: * Retrieves this attribute's schema definition.
209: *
210: * @return This attribute's schema definition.
211: */
212: public DirContext getAttributeDefinition() throws NamingException {
213: DirContext schema = getBaseCtx().getSchema(rdn);
214:
215: return (DirContext) schema
216: .lookup(LdapSchemaParser.ATTRIBUTE_DEFINITION_NAME
217: + "/" + getID());
218: }
219: }
|