Compare commits

..

1 Commits

Author SHA1 Message Date
(no author)
3e9dfe2fe4 This commit was manufactured by cvs2svn to create tag 'LDAPJavaSDK_416'.
git-svn-id: svn://10.0.0.236/tags/LDAPJavaSDK_416@120127 18797224-902f-48f8-a5cc-f745e15eee43
2002-04-27 23:41:16 +00:00
396 changed files with 92387 additions and 201 deletions

View File

@@ -0,0 +1,208 @@
======================================================================
NETSCAPE DIRECTORY SDK FOR JAVA:
BUILD INSTRUCTIONS
Last updated: August 2, 1999
======================================================================
For information on the Netscape Directory SDK source release,
see http://www.mozilla.org/directory/
Note the following:
- The LDAP filter classes (in the netscape.ldap.util package)
use the OROMatcher(tm) regular expression package (from ORO Java Software).
This is not provided with the source code release. If you want this
package, you need to get it from ORO, Inc. (For details, see the
ORO, Inc. home page at http://www.oroinc.com/.)
Unix/Linux Build Instructions
-----------------------------
System Requirements:
32MB of RAM, 128MB of swap, recommended 64MB of RAM.
Tool Requirements:
Sun Microsystems Java Development Kit (JDK) 1.1.7
(or a more recent version)
GNU make 3.74 or a more recent version
Instructions:
1. Uncompress and extract the source files by entering the
following command (or your preferred variant of this command):
gzip -dc <filename>.tar.gz | tar -xvf -
2. Set and unset the following environment variables.
In csh/tcsh:
setenv JAVA_HOME "<directory where the JDK is installed>"
For example:
setenv JAVA_HOME "/usr/local/jdk1.1.7"
setenv CLASSPATH "<location of the JDK classes.zip file>"
For example:
setenv CLASSPATH "/usr/local/jdk1.1.7/lib/classes.zip"
In sh/bash/ksh:
JAVA_HOME="<directory where the JDK is installed>"
CLASSPATH="<location of the JDK classes.zip file>"
export JAVA_HOME CLASSPATH
3. Build the LDAP Java classes by entering the following commands:
cd mozilla/directory/java-sdk
gmake -f ldap.mk
If you also want the classes packaged in a JAR file,
specify "basepackage" as the target:
gmake -f ldap.mk basepackage
To generate javadoc specify "doc" as the target:
gmake -f ldap.mk doc
Note that if you are using JDK1.1, javadoc images will be missing
and you'll need to copy those images from somewhere else into
mozilla/directory/java-sdk/dist/doc/images. If you are using JDK1.2
you do not need to do that.
The SDK will be built and copied into the following directories:
mozilla/directory/java-sdk/dist/classes - class files and manifest file
mozilla/directory/java-sdk/dist/packages - ldapjdk.jar JAR file
(if you've specified "basepackage" as the target)
mozilla/directory/java-sdk/dist/doc - ldapjdk javadoc
(if you've specified "doc" as the target)
4. Build the JNDI LDAP Service Provider classes by entering the following commands:
gmake -f ldapsp.mk
If you also want the classes packaged in a JAR file,
specify "basepackage" as the target:
gmake -f ldapsp.mk basepackage
To generate javadoc specify "doc" as the target:
gmake -f ldapsp.mk doc
The SDK will be built and copied into the following directories:
mozilla/directory/java-sdk/dist/classes - class files
mozilla/directory/java-sdk/dist/packages - ldapsp.jar JAR file
(if you've specified "basepackage" as the target)
mozilla/directory/java-sdk/dist/doc/ldapsp - ldapsp controls' javadoc
(if you've specified "doc" as the target)
The JNDI LDAP Service Provider depends on the LDAP Java classes, so you
always must build the LDAP Java first. For more information on JNDI see
ldapsp/Readme.html and http://java.sun.com/products/jndi/index.html
Windows Build Instructions
--------------------------
System Requirements:
Windows NT 3.51 or 4.0 (4.0 preferred).
Tool Requirements:
Sun Microsystems Java Development Kit (JDK) 1.1.7
(or a more recent version)
GNU Tools for Windows (you can find these on the Internet).
Specifically, you'll need:
cp.exe
rm.exe
Here are some sample download sites to find these:
Cygnus (http://www.cygnus.com/misc/gnu-win32)
GNU (http://www.gnu.org/order/ftp.html)
MIT (ftp://prep.ai.mit.edu/pub/gnu)
Netscape uses internally modified versions of the following tools:
gmake.exe
shmsdos.exe
uname.exe
You can download them from http://www.mozilla.org/download-mozilla.html
(click the Windows Build Tools link). When you unzip the file, the
tools will be located in the windows\bin\x86 directory.
All of these tools need to be put in your path.
Extracting the Source Files:
The source files for the Directory SDK are zipped in a file.
When unzipping the file, make sure to specify that you want to
preserve the directory structure. For example,
make sure that "Use Folder Names" is checked.
Instructions:
NOTE: Make sure to run the commands from a standard Windows NT
command prompt. Although you may be able to use other shells
to build the SDK, you may need to adjust the makefiles for
the shell that you are using.
1. Set the following environment variables (within the command session,
either manually or via a script), or within the system environment
through the Control Panel | System control panel):
set MOZ_SRC=(top of your source tree, drive letter and path.
For example, set MOZ_SRC=d:\mozilla_src, if the mozilla
directory is at d:\mozilla_src\mozilla.)
set JAVA_HOME=(directory where the JDK is installed)
For example:
set JAVA_HOME=D:\jdk1.1.7
set CLASSPATH=(location of the JDK classes.zip file)
For example:
set CLASSPATH=D:\jdk1.1.7\lib\classes.zip
In addition, make sure to set your PATH environment variable to
include the tools that you have downloaded.
2. Enter the following commands to build the LDAP Java classes:
cd mozilla\directory\java-sdk
gmake -f ldap.mk
If you also want the classes packaged in a JAR file,
specify "basepackage" as the target:
gmake -f ldap.mk basepackage
To generate javadoc specify "doc" as the target:
gmake -f ldap.mk doc
Note that if you are using JDK1.1, javadoc images will be missing
and you'll need to copy those images from somewhere else into
mozilla\directory\java-sdk\dist\doc\images. If you are using JDK1.2
you do not need to do that.
The SDK will be built and copied into the following directories:
mozilla\directory\java-sdk\dist\classes - class files and manifest file
mozilla\directory\java-sdk\dist\packages - ldapjdk.jar JAR file
(if you've specified "basepackage" as the target)
mozilla\directory\java-sdk\dist\doc - ldapjdk javadoc
(if you've specified "doc" as the target)
3. Build the JNDI LDAP Service Provider classes by entering the following commands:
gmake -f ldapsp.mk
If you also want the classes packaged in a JAR file,
specify "basepackage" as the target:
gmake -f ldapsp.mk basepackage
To generate javadoc specify "doc" as the target:
gmake -f ldapsp.mk doc
The SDK will be built and copied into the following directories:
mozilla/directory/java-sdk/dist/classes - class files
mozilla/directory/java-sdk/dist/packages - ldapsp.jar JAR file
(if you've specified "basepackage" as the target)
mozilla\directory\java-sdk\dist\doc\ldapsp - ldapsp controls' javadoc
(if you've specified "doc" as the target)
The JNDI LDAP Service Provider depends on the LDAP Java classes, so you
always must build the LDAP Java first. For more information on JNDI see
ldapsp/Readme.html and http://java.sun.com/products/jndi/index.html
--------------------------------------------------------
Copyright (c) 1999 Netscape Communications Corporation.
(http://home.netscape.com/misc/contact_info.html)

View File

@@ -0,0 +1,30 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"><meta name="author" content="Rob Weltman">
<title>The Mozilla implementation of org.ietf.ldap</title>
</head><body>
<h2>The Mozilla implementation of org.ietf.ldap</h2>
<br>
<i><small>Rob Weltman</small><small><br></small><small>November 8, 2001</small></i><br>
&nbsp;<br>
This is a new branch of the Directory SDK for Java that complies with the
proposed IETF standard API. While very similar to the netscape.ldap branch,
it is different enough that just changing your import statements from "import
netscape.ldap.*;" to "import org.ietf.ldap.*;" won't let you compile. There
will be a migration guide and sample apps soon.<br>
<br>
The code requires JDK 1.2 or higher, or JDK 1.8 if you have the Collections classes in your CLASSPATH.<br>
<br>
Build the SDK with <a href="http://jakarta.apache.org/ant/">ant</a>
.
<ul>
<li>ant &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Compiles and creates a JAR file</li>
<li>ant javadoc &nbsp; &nbsp;Generates javadocs</li>
</ul>
At this point, consider the branch to be of Alpha quality. It implements
just about everything in the IETF API except for startTLS and stopTLS.<br>
<br>
SASL clients will require the new Java SASL API being defined in <a href="http://www.jcp.org/jsr/detail/28.jsp">JSR 28</a>
in the JCP. There are <a href="http://www.worldspot.com/jsr28/">docs</a>
for the proposed new API that you can browse. Soon there will be a Reference Implementation for download.<br>
<br>
</body></html>

View File

@@ -0,0 +1,151 @@
<?xml version="1.0"?>
<!-- This file is intended for ANT, a Java based build tool. -->
<!-- ANT is availale from http://jakarta.apache.org/ant/index.html -->
<!-- The default target includes compiling and making JAR files -->
<project default="jars" basedir=".">
<!-- ##################################################### -->
<!-- # Usage # -->
<!-- ##################################################### -->
<target name="usage">
<echo>
ant compile -> compiles source files
ant jars -> makes jar files of compiled source
ant clean -> guess
</echo>
</target>
<!-- ##################################################### -->
<!-- # Set Version numbers # -->
<!-- # used only in Javadoc? # -->
<!-- ##################################################### -->
<property name="name" value="ietfldap"/>
<property name="version" value="0.1"/>
<property name="year" value="2001"/>
<!--
<property name="build.compiler" value="classic"/>
-->
<property name="debug" value="on"/>
<property name="src.dir" value="."/>
<property name="packages" value="org.*"/>
<property name="build.file" value="build.xml"/>
<property name="build.dir" value="."/>
<property name="build.dest" value="./classes"/>
<property name="build.lib" value="./lib"/>
<property name="build.javadocs" value="./javadoc"/>
<property name="javadoc.private" value="false"/>
<property name="javadoc.protected" value="false"/>
<path id="javadoc.path">
<pathelement location="${src.dir}"/>
</path>
<property name="jaas.dir" value="../ldapjdk/lib"/>
<property name="jsse.dir" value="../ldapjdk/lib"/>
<property name="jnet.dir" value="../ldapjdk/lib"/>
<property name="sasl.dir" value="../ldapjdk/lib"/>
<!-- ##################################################### -->
<!-- # construct the classpath # -->
<!-- ##################################################### -->
<path id="class.path">
<pathelement location="${jaas.dir}/jaas.jar"/>
<pathelement location="${jsse.dir}/jsse.jar"/>
<pathelement location="${jsse.dir}/jnet.jar"/>
<pathelement location="${sasl.dir}/sasl.jar"/>
<pathelement location="${build.dest}"/>
<pathelement location="."/>
</path>
<property name="classpath" refid="class.path"/>
<!-- ##################################################### -->
<!-- # init - anything that needs to be done first of all# -->
<!-- ##################################################### -->
<target name="init">
<!-- Set the NOW property to the current time -->
<tstamp>
<format property="NOW" pattern="MMMM dd yyyy HH:mm"/>
</tstamp>
</target>
<!-- ##################################################### -->
<!-- # classpath - echo the CLASSPATH that would be used # -->
<!-- ##################################################### -->
<target name="classpath">
<echo message="${classpath}"/>
</target>
<!-- ##################################################### -->
<!-- # compile # -->
<!-- ##################################################### -->
<target name="compile" depends="init">
<mkdir dir="${build.dest}"/>
<javac srcdir="${src.dir}"
destdir="${build.dest}"
debug="${debug}"
excludes="${build.excludes}"
deprecation="on"
classpathref="class.path"/>
<copy todir="${build.dest}" >
<fileset dir="${src.dir}">
<exclude name="classes/**"/>
<include name="**/*.properties"/>
</fileset>
</copy>
</target>
<!-- ##################################################### -->
<!-- # jars # -->
<!-- ##################################################### -->
<target name="jars" depends="compile">
<mkdir dir="${build.lib}"/>
<jar jarfile="${build.lib}/${name}.jar"
basedir="${build.dest}"
includes="org/ietf/ldap/** LDAP*.class">
</jar>
</target>
<!-- ##################################################### -->
<!-- # javadoc # -->
<!-- ##################################################### -->
<target name="javadoc" depends="init">
<mkdir dir="${build.javadocs}"/>
<javadoc packagenames="${packages}"
sourcepathref="javadoc.path"
classpathref="class.path"
destdir="${build.javadocs}"
private="${javadoc.private}"
protected="${javadoc.protected}"
author="true"
version="true"
use="true"
windowtitle="${name} API as of ${NOW}"
link="http://java.sun.com/j2se/1.3/docs/api"
doctitle="${name}"
bottom="Subject to Netscape Public License">
<group title="Utilities" packages="org.ietf.ldap.util*"/>
<group title="Controls" packages="org.ietf.ldap.controls*"/>
<link href="http://java.sun.com/products/jdk/1.3/docs/api"/>
</javadoc>
</target>
<!-- ##################################################### -->
<!-- # clean # -->
<!-- ##################################################### -->
<target name="clean">
<delete dir="${build.dest}"/>
<delete dir="${build.lib}"/>
<delete dir="${build.javadocs}"/>
</target>
</project>

View File

@@ -0,0 +1,115 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.lang.reflect.*;
import java.util.Hashtable;
/**
* Utility class to dynamically find methods of a class and to invoke
* them
*/
class DynamicInvoker {
static Object invokeMethod( Object obj,
String packageName,
String methodName,
Object[] args,
String[] argNames )
throws LDAPException {
try {
java.lang.reflect.Method m = getMethod( packageName,
methodName,
argNames );
if ( m != null ) {
return m.invoke( obj, args );
} else {
System.err.println( "No such method: " +
packageName + "." + methodName );
}
} catch ( Exception e ) {
e.printStackTrace();
throw new LDAPException( "Invoking " + methodName + ": " +
e.toString(),
LDAPException.PARAM_ERROR );
}
return null;
}
static Method getMethod( String packageName,
String methodName,
String[] args ) throws LDAPException {
try {
Method method = null;
String suffix = "";
if ( args != null ) {
for ( int i = 0; i < args.length; i++ ) {
suffix = suffix + args[i].getClass().getName();
}
}
String key = packageName + "." + methodName + "." + suffix;
if ( (method = (Method)(m_methodLookup.get(key))) != null ) {
return method;
}
Class c = Class.forName( packageName );
Method[] m = c.getMethods();
for ( int i = 0; i < m.length; i++ ) {
Class[] params = m[i].getParameterTypes();
if ( m[i].getName().equals(methodName) &&
signatureCorrect( params, args ) ) {
m_methodLookup.put( key, m[i] );
return m[i];
}
}
throw new LDAPException( "Method " +
methodName +
" not found in " +
packageName );
} catch ( ClassNotFoundException e ) {
throw new LDAPException( "Class " + packageName + " not found" );
}
}
static private boolean signatureCorrect( Class params[],
String args[] ) {
if ( args == null ) {
return true;
}
if ( params.length != args.length ) {
System.err.println( params.length + " method parameters vs " +
args.length + " expected" );
return false;
}
for ( int i = 0; i < params.length; i++ ) {
if ( !params[i].getName().equals(args[i]) ) {
System.err.println( params[i].getName() +
" method parameter vs " +
args[i] + " expected" );
return false;
}
}
return true;
}
private static Hashtable m_methodLookup = new Hashtable();
}

View File

@@ -0,0 +1,560 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.io.*;
import java.util.*;
import org.ietf.ldap.ber.stream.*;
/**
* Represents the name and values of an attribute in an entry.
*
* @version 1.0
* @see org.ietf.ldap.LDAPAttributeSet
*/
public class LDAPAttribute implements Cloneable, Serializable {
static final long serialVersionUID = -4594745735452202600L;
private String name = null;
private byte[] nameBuf = null;
/**
* Internally, this is a list of "byte[]"-based attribute values.
*/
private Object values[] = new Object[0];
/**
* Constructs an attribute from another existing attribute.
* Effectively, this makes a copy of the existing attribute.
* @param attr the attribute to copy
*/
public LDAPAttribute( LDAPAttribute attr ) {
name = attr.name;
nameBuf = attr.nameBuf;
values = new Object[attr.values.length];
for (int i = 0; i < attr.values.length; i++) {
values[i] = new byte[((byte[])attr.values[i]).length];
System.arraycopy((byte[])attr.values[i], 0, (byte[])values[i], 0,
((byte[])attr.values[i]).length);
}
}
/**
* Constructs an attribute with no values.
* @param attrName name of the attribute
*/
public LDAPAttribute( String attrName ) {
name = attrName;
}
/**
* Constructs an attribute with a byte-formatted value.
* @param attrName name of the attribute
* @param attrValue value of the attribute in byte format
*/
public LDAPAttribute( String attrName, byte[] attrValue ) {
name = attrName;
addValue(attrValue);
}
/**
* Constructs an attribute that has a single string value.
* @param attrName name of the attribute
* @param attrValue value of the attribute in String format
*/
public LDAPAttribute( String attrName, String attrValue ) {
name = attrName;
addValue( attrValue );
}
/**
* Constructs an attribute that has an array of string values.
* @param attrName name of the attribute
* @param attrValues the list of string values for this attribute
*/
public LDAPAttribute( String attrName, String[] attrValues ) {
name = attrName;
if (attrValues != null) {
setValues( attrValues );
}
}
/**
* Constructs an attribute from a BER (Basic Encoding Rules) element.
* (The protocol elements of LDAP are encoded for exchange using the
* Basic Encoding Rules.)
* @param element element that you want translated into an attribute
* @exception IOException The attribute could not be created from
* the specified element.
*/
public LDAPAttribute(BERElement element) throws IOException {
BERSequence seq = (BERSequence)element;
BEROctetString type = (BEROctetString)seq.elementAt(0);
nameBuf = type.getValue();
BERSet set = (BERSet)seq.elementAt(1);
if (set.size() > 0) {
Object[] vals = new Object[set.size()];
for (int i = 0; i < set.size(); i++) {
vals[i] = ((BEROctetString)set.elementAt(i)).getValue();
if (vals[i] == null) {
vals[i] = new byte[0];
}
}
setValues( vals );
}
}
/**
* Returns the number of values of the attribute.
* @return number of values for this attribute.
*/
public int size() {
return values.length;
}
/**
* Returns an enumerator for the string values of an attribute.
* @return enumerator for the string values.
*/
public Enumeration getStringValues() {
Vector v = new Vector();
synchronized(this) {
try {
for (int i=0; i<values.length; i++) {
if ( values[i] != null ) {
v.addElement(new String ((byte[])values[i], "UTF8"));
} else {
v.addElement( new String( "" ) );
}
}
} catch ( Exception e ) {
return null;
}
}
return v.elements();
}
/**
* Returns the values of the attribute as an array of <CODE>String</CODE>
* objects.
* @return array of attribute values. Each element in the array
* is a <CODE>String</CODE> object.
*/
public String[] getStringValueArray() {
String s[] = new String[values.length];
synchronized(this) {
try {
for (int i=0; i < values.length; i++) {
if ( values[i] !=null ) {
s[i] = new String((byte[])values[i], "UTF8");
} else {
s[i] = new String("");
}
}
} catch (Exception e) {
return null;
}
}
return s;
}
/**
* Returns an enumerator for the values of the attribute in <CODE>byte[]</CODE>
* format.
* @return a set of attribute values. Each element in the enumeration
* is of type <CODE>byte[]</CODE>.
*/
public Enumeration getByteValues() {
Vector v = new Vector();
synchronized(this) {
for (int i=0; i<values.length; i++) {
if ( values[i] != null ) {
v.addElement(values[i]);
} else {
v.addElement( new byte[0] );
}
}
}
return v.elements();
}
/**
* Returns the values of the attribute in an array of <CODE>byte[]</CODE>
* format.
* @return array of attribute values. Each element in the array
* will be of type <CODE>byte[]</CODE>.
*/
public byte[][] getByteValueArray() {
byte b[][] = new byte[values.length][];
synchronized(this) {
try {
for (int i=0; i < values.length; i++) {
b[i] = new byte[((byte[])(values[i])).length];
System.arraycopy((byte[])values[i], 0, (byte[])b[i], 0,
((byte[])(values[i])).length);
}
} catch (Exception e) {
return null;
}
}
return b;
}
/**
* Returns the name of the attribute.
* @return name of the attribute.
*/
public String getName() {
if ((name == null) && (nameBuf != null)) {
try{
name = new String(nameBuf, "UTF8");
} catch(Throwable x) {}
}
return name;
}
/**
* Extracts the subtypes from the specified attribute name.
* For example, if the attribute name is <CODE>cn;lang-ja;phonetic</CODE>,
* this method returns an array containing <CODE>lang-ja</CODE>
* and <CODE>phonetic</CODE>.
* <P>
*
* @param attrName name of the attribute from which to extract the subtypes
* @return array of subtypes, or null (if the name has no subtypes).
* @see org.ietf.ldap.LDAPAttribute#getBaseName
*/
public static String[] getSubtypes(String attrName) {
StringTokenizer st = new StringTokenizer(attrName, ";");
if( st.hasMoreElements() ) {
// First element is base name
st.nextElement();
String[] subtypes = new String[st.countTokens()];
int i = 0;
// Extract the types
while( st.hasMoreElements() )
subtypes[i++] = (String)st.nextElement();
return subtypes;
}
return null;
}
/**
* Extracts the subtypes from the attribute name of the current
* <CODE>LDAPAttribute</CODE> object. For example, if the attribute
* name is <CODE>cn;lang-ja;phonetic</CODE>, this method returns an array
* containing <CODE>lang-ja</CODE> and <CODE>phonetic</CODE>.
*<P>
*
* @return array of subtypes, or null (if the name has no subtypes).
*/
public String[] getSubtypes() {
return getSubtypes(getName());
}
/**
* Extracts the language subtype from the attribute name of the
* <CODE>LDAPAttribute</CODE> object, if any. For example, if the
* attribute name is <CODE>cn;lang-ja;phonetic</CODE>, this method
* returns the String <CODE>lang-ja</CODE>.
*<P>
*
* @return the language subtype, or null (if the name has no
* language subtype).
*/
public String getLangSubtype() {
String[] subTypes = getSubtypes();
if ( subTypes != null ) {
for( int i = 0; i < subTypes.length; i++ ) {
if ((subTypes[i].length() >= 5) &&
(subTypes[i].substring(0, 5).equalsIgnoreCase("lang-")))
return subTypes[i];
}
}
return null;
}
/**
* Extracts the base name from the specified attribute name.
* For example, if the attribute name is <CODE>cn;lang-ja;phonetic</CODE>,
* this method returns <CODE>cn</CODE>.
* <P>
*
* @param attrName name of the attribute from which to extract the base name
* @return base name (the attribute name without any subtypes).
* @see org.ietf.ldap.LDAPAttribute#getSubtypes
*/
public static String getBaseName( String attrName ) {
String basename = attrName;
StringTokenizer st = new StringTokenizer(attrName, ";");
if( st.hasMoreElements() )
// First element is base name
basename = (String)st.nextElement();
return basename;
}
/**
* Extracts the base name from the attribute name of the current
* <CODE>LDAPAttribute</CODE> object. For example, if the attribute
* name is <CODE>cn;lang-ja;phonetic</CODE>, this method returns
* <CODE>cn</CODE>.
* <P>
*
* @return base name (the attribute name without any subtypes).
* @see org.ietf.ldap.LDAPAttribute#getSubtypes
*/
public String getBaseName() {
return getBaseName(getName());
}
/**
* Reports whether the attribute name contains the specified subtype.
* For example, if you check for the subtype <CODE>lang-en</CODE>
* and the attribute name is <CODE>cn;lang-en</CODE>, this method
* returns <CODE>true</CODE>.
* <P>
*
* @param subtype the single subtype for which you want to check
* @return true if the attribute name contains the specified subtype.
* @see org.ietf.ldap.LDAPAttribute#getSubtypes
*/
public boolean hasSubtype( String subtype ) {
String[] mytypes = getSubtypes();
for(int i = 0; i < mytypes.length; i++) {
if( subtype.equalsIgnoreCase( mytypes[i] ) )
return true;
}
return false;
}
/**
* Reports if the attribute name contains all specified subtypes
* For example, if you check for the subtypes <CODE>lang-en</CODE>
* and <CODE>phonetic</CODE> and the attribute name is
* <CODE>cn;lang-en;phonetic</CODE>, this method returns <CODE>true</CODE>.
* If the attribute name is <CODE>cn;phonetic</CODE> or
* <CODE>cn;lang-en</CODE>, this method returns <CODE>false</CODE>.
* <P>
* @param subtypes an array of subtypes to check
* @return true if the attribute name contains all subtypes
* @see org.ietf.ldap.LDAPAttribute#getSubtypes
*/
public boolean hasSubtypes( String[] subtypes ) {
for(int i = 0; i < subtypes.length; i++) {
if( !hasSubtype(subtypes[i]) )
return false;
}
return true;
}
/**
* Adds a string value to the attribute.
* @param attrValue the string value to add to the attribute
*/
public synchronized void addValue( String attrValue ) {
if (attrValue != null) {
try {
byte[] b = attrValue.getBytes("UTF8");
addValue( b );
} catch(Throwable x)
{}
}
}
/**
* Sets the string values as the attribute's values.
* @param attrValues the string values to use in the attribute
*/
protected void setValues( String[] attrValues ) {
Object[] vals;
if (attrValues != null) {
vals = new Object[attrValues.length];
for (int i = 0; i < vals.length; i++) {
try {
vals[i] = attrValues[i].getBytes("UTF8");
} catch(Throwable x)
{ vals[i] = new byte[0]; }
}
} else {
vals = new Object[0];
}
setValues(vals);
}
/**
* Adds a <CODE>byte[]</CODE>-formatted value to the attribute.
* @param attrValue the <CODE>byte[]</CODE>-formatted value to
* add to the attribute
*/
public synchronized void addValue( byte[] attrValue ) {
if (attrValue != null) {
Object[] vals = new Object[values.length+1];
for (int i = 0; i < values.length; i++)
vals[i] = values[i];
vals[values.length] = attrValue;
values = vals;
}
}
/**
* Sets the byte[] values as the attribute's values.
* @param attrValues the values to use in the attribute
*/
protected synchronized void setValues( Object[] attrValues ) {
values = attrValues;
}
/**
* Removes a string value from the attribute.
* @param attrValue the string value to remove
*/
public synchronized void removeValue( String attrValue) {
if (attrValue != null) {
try{
byte b[] = attrValue.getBytes("UTF8");
removeValue ( b );
} catch(Throwable x)
{}
}
}
/**
* Removes a <CODE>byte[]</CODE>-formatted value from the attribute.
* @param attrValue <CODE>byte[]</CODE>-formatted value to remove
*/
public synchronized void removeValue( byte[] attrValue) {
if ((attrValue == null) || (values == null)|| (values.length < 1))
return;
int ind = -1;
for (int i=0; i<values.length; i++) {
if (equalValue(attrValue, (byte[])values[i])) {
ind = i;
break;
}
}
if (ind >= 0) {
Object[] vals = new Object[values.length-1];
int j = 0;
for (int i = 0; i < values.length; i++) {
if (i != ind) {
vals[j++] = values[i];
}
}
values = vals;
}
}
private static boolean equalValue(byte[] a, byte[] b) {
if (a.length != b.length)
return false;
for (int i=0; i<a.length; i++) {
if (a[i] != b[i])
return false;
}
return true;
}
/**
* Retrieves the BER (Basic Encoding Rules) representation of an attribute.
* (The protocol elements of LDAP are encoded for exchange using the
* Basic Encoding Rules.)
* @return the BER representation of the attribute.
*/
public BERElement getBERElement() {
try {
BERSequence seq = new BERSequence();
seq.addElement(new BEROctetString(getName()));
BERSet set = new BERSet();
for (int i = 0; i < values.length; i++) {
set.addElement(new BEROctetString((byte[])values[i]));
}
seq.addElement(set);
return seq;
} catch (IOException e) {
return null;
}
}
/**
* Retrieves the string representation of attribute parameters.
* @return string representation parameters.
*/
private String getParamString() {
StringBuffer sb = new StringBuffer();
if ( values.length > 0 ) {
for (int i = 0; i < values.length; i++) {
if (i != 0) {
sb.append(",");
}
byte[] val = (byte[])values[i];
try {
String sval = new String(val, "UTF8");
if (sval.length() == 0 && val.length > 0) {
sb.append("<binary value, length:");
sb.append(val.length);
sb.append(">");
}
else {
sb.append(sval);
}
} catch (Exception e) {
if (val != null) {
sb.append("<binary value, length:");
sb.append(val.length);
sb.append(">");
}
else {
sb.append("null value");
}
}
}
}
return "{type='" + getName() + "', values='" + sb.toString() + "'}";
}
/**
* Creates and returns a new <CODE>LDAPAttribute</CODE> object that
* contains the same information as this one. The cloned object has
* a deep copy of the contents of the original.
*
* @return A deep copy of this object
*/
public synchronized Object clone() {
return new LDAPAttribute( this );
}
/**
* Retrieves the string representation of an attribute
* in an LDAP entry. For example:
*
* <PRE>LDAPAttribute {type='cn', values='Barbara Jensen,Babs Jensen'}</PRE>
*
* @return string representation of the attribute.
*/
public String toString() {
return "LDAPAttribute " + getParamString();
}
}

View File

@@ -0,0 +1,468 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
/**
* The definition of an attribute type in the schema.
* <A HREF="http://www.ietf.org/rfc/rfc2252.txt"
* TARGET="_blank">RFC 2252, Lightweight Directory Access Protocol (v3):
* Attribute Syntax Definitions</A> covers the types of information
* to specify when defining an attribute type. According to the RFC,
* the description of an attribute type can include the following:
* <P>
*
* <UL>
* <LI>an OID identifying the attribute type
* <LI>a name identifying the attribute type
* <LI>a description of the attribute type
* <LI>the name of the parent attribute type
* <LI>the syntax used by the attribute (for example,
* <CODE>cis</CODE> or <CODE>int</CODE>)
* <LI>an indication of whether the attribute type is single-valued
* or multi-valued
* </UL>
* <P>
*
* When you construct an <CODE>LDAPAttributeSchema</CODE> object, you can
* specify these types of information as arguments to the constructor or
* in the AttributeTypeDescription format specified in RFC 2252.
* When an LDAP client searches an LDAP server for the schema, the server
* returns schema information as an object with attribute values in this
* format.
* <P>
*
* There a number of additional optional description fields which
* are not explicitly accessible through LDAPAttributeSchema, but which
* can be managed with setQualifier, getQualifier, and getQualifierNames:
* <P>
*
* <UL>
* <LI>EQUALITY
* <LI>ORDERING
* <LI>SUBSTR
* <LI>COLLECTIVE
* <LI>NO-USER-MODIFICATION
* <LI>USAGE
* <LI>OBSOLETE
* </UL>
* <P>
*
* To get the name, OID, and description of this attribute type
* definition, use the <CODE>getName</CODE>, <CODE>getOID</CODE>, and
* <CODE>getDescription</CODE> methods inherited from the abstract class
* <CODE>LDAPSchemaElement</CODE>. Optional and custom qualifiers are
* accessed with <CODE>getQualifier</CODE> and <CODE>getQualifierNames</CODE>
* from <CODE>LDAPSchemaElement</CODE>.
* <P>
*
* To add or remove this attribute type definition from the
* schema, use the <CODE>add</CODE> and <CODE>remove</CODE>
* methods, which this class inherits from the <CODE>LDAPSchemaElement</CODE>
* abstract class.
* <P>
* RFC 2252 defines AttributeTypeDescription as follows:
* <P>
* <PRE>
* AttributeTypeDescription = "(" whsp
* numericoid whsp ; AttributeType identifier
* [ "NAME" qdescrs ] ; name used in AttributeType
* [ "DESC" qdstring ] ; description
* [ "OBSOLETE" whsp ]
* [ "SUP" woid ] ; derived from this other
* ; AttributeType
* [ "EQUALITY" woid ; Matching Rule name
* [ "ORDERING" woid ; Matching Rule name
* [ "SUBSTR" woid ] ; Matching Rule name
* [ "SYNTAX" whsp noidlen whsp ] ; see section 4.3
* [ "SINGLE-VALUE" whsp ] ; default multi-valued
* [ "COLLECTIVE" whsp ] ; default not collective
* [ "NO-USER-MODIFICATION" whsp ]; default user modifiable
* [ "USAGE" whsp AttributeUsage ]; default userApplications
* whsp ")"
*
* AttributeUsage =
* "userApplications" /
* "directoryOperation" /
* "distributedOperation" / ; DSA-shared
* "dSAOperation" ; DSA-specific, value depends on server
* </PRE>
*
* @version 1.0
* @see org.ietf.ldap.LDAPSchemaElement
**/
public class LDAPAttributeSchema extends LDAPSchemaElement {
static final long serialVersionUID = 2482595821879862595L;
/**
* Constructs a blank element.
*/
protected LDAPAttributeSchema() {
super();
}
/**
* Constructs an attribute type definition, using the specified
* information
* @param names names of the attribute type
* @param oid object identifier (OID) of the attribute type
* in dotted-string format (for example, "1.2.3.4")
* @param description description of attribute type
* @param syntaxString syntax of this attribute type in dotted-string
* format (for example, "1.2.3.4.5")
* @param single <CODE>true</CODE> if the attribute type is single-valued
* @param superior superior attribute as a name or OID; <CODE>null</CODE>
* if there is no superior
* @param obsolete true if this attribute is obsolete
* @param equality Object Identifier of the equality matching rule
* for the attribute in dotted-decimal format; MAY be null
* @param ordering Object Identifier of the ordering matching rule
* for the attribute in dotted-decimal format; MAY be null
* @param substring Object Identifier of the substring matching rule
* for the attribute in dotted-decimal format; MAY be null
* @param collective true if this is a collective attribute.
* @param userMod true if the attribute is modifiable by users.
* @param usage One of the following:
* <UL>
* <LI>USER_APPLICATIONS
* <LI>DIRECTORY_OPERATION
* <LI>DISTRIBUTED_OPERATION
* <LI>DSA_OPERATION
* </UL>
*/
public LDAPAttributeSchema( String[] names,
String oid,
String description,
String syntaxString,
boolean single,
String superior,
boolean obsolete,
String equality,
String ordering,
String substring,
String collective,
boolean userMod,
int usage ) {
super( names, oid, description );
attrName = "attributetypes";
syntaxElement.syntax = syntaxElement.syntaxCheck( syntaxString );
syntaxElement.syntaxString = syntaxString;
setQualifier( SYNTAX, syntaxElement.syntaxString );
if ( single ) {
setQualifier( SINGLE, "" );
}
if ( (superior != null) && (superior.length() > 0) ) {
setQualifier( SUPERIOR, superior );
}
if ( obsolete ) {
setQualifier( OBSOLETE, "" );
}
if ( (equality != null) && (equality.length() > 0) ) {
setQualifier( EQUALITY, equality );
}
if ( (ordering != null) && (ordering.length() > 0) ) {
setQualifier( ORDERING, ordering );
}
if ( (substring != null) && (substring.length() > 0) ) {
setQualifier( SUBSTR, substring );
}
if ( (collective != null) && (collective.length() > 0) ) {
setQualifier( COLLECTIVE, collective );
}
if ( !userMod ) {
setQualifier( NO_USER_MODIFICATION, "" );
}
setQualifier( USAGE, String.valueOf( usage ) );
}
/**
* Constructs an attribute type definition based on a description in
* the AttributeTypeDescription format. For information on this format,
* (see <A HREF="http://www.ietf.org/rfc/rfc2252.txt"
* TARGET="_blank">RFC 2252, Lightweight Directory Access Protocol (v3):
* Attribute Syntax Definitions</A>. This is the format that LDAP servers
* and clients use to exchange schema information. (For example, when
* you search an LDAP server for its schema, the server returns an entry
* with the attributes "objectclasses" and "attributetypes". The
* values of "attributetypes" are attribute type descriptions
* in this format.)
* <P>
*
* @param raw definition of the attribute type in the
* AttributeTypeDescription format
*/
public LDAPAttributeSchema( String raw ) {
attrName = "attributetypes";
parseValue( raw );
String val = (String)properties.get( SYNTAX );
if ( val != null ) {
syntaxElement.syntaxString = val;
syntaxElement.syntax = syntaxElement.syntaxCheck( val );
}
}
/**
* Returns the value of a property of the object or null if there is none
*
* @param key the name of the property
* @return the value of a property of the object or null if there is none
*/
private String getStringProperty( String key ) {
String[] val = getQualifier( key );
return ((val != null) && (val.length > 0)) ? val[0] : null;
}
/**
* Returns the Object Identifier of the equality matching rule in effect
* for this attribute, or null if there is none
* @return the Object Identifier of the equality matching rule in effect
* for this attribute, or null if there is none
*/
public String getEqualityMatchingRule() {
return getStringProperty( EQUALITY );
}
/**
* Returns the Object Identifier of the order matching rule in effect
* for this attribute, or null if there is none
* @return the Object Identifier of the order matching rule in effect
* for this attribute, or null if there is none
*/
public String getOrderMatchingRule() {
return getStringProperty( ORDERING );
}
/**
* Returns the Object Identifier of the substring matching rule in effect
* for this attribute, or null if there is none
* @return the Object Identifier of the substring matching rule in effect
* for this attribute, or null if there is none
*/
public String getSubstringMatchingRule() {
return getStringProperty( SUBSTR );
}
/**
* Gets the name of the attribute that this attribute inherits from,
* if any.
* @return the name of the attribute from which this attribute
* inherits, or <CODE>null</CODE> if it does not have a superior.
*/
public String getSuperior() {
return getStringProperty( SUPERIOR );
}
/**
* Gets the syntax of the schema element
* @return one of the following values:
* <UL>
* <LI><CODE>cis</CODE> (case-insensitive string)
* <LI><CODE>ces</CODE> (case-exact string)
* <LI><CODE>binary</CODE> (binary data)
* <LI><CODE>int</CODE> (integer)
* <LI><CODE>telephone</CODE> (telephone number -- identical to cis,
* but blanks and dashes are ignored during comparisons)
* <LI><CODE>dn</CODE> (distinguished name)
* <LI><CODE>unknown</CODE> (not a known syntax)
* </UL>
* @deprecated use getSyntaxString instead
*/
public int getSyntax() {
return syntaxElement.syntax;
}
/**
* Gets the usage property of the object
*
* @return the usage property of the object; one of the following:
* <UL>
* <LI>USER_APPLICATIONS
* <LI>DIRECTORY_OPERATION
* <LI>DISTRIBUTED_OPERATION
* <LI>DSA_OPERATION
* </UL>
*/
public int getUsage() {
int usage;
try {
usage = Integer.parseInt( getStringProperty( USAGE ) );
} catch ( Exception e ) {
usage = USER_APPLICATIONS;
}
return usage;
}
/**
* Gets the syntax of the attribute type in dotted-decimal format,
* for example "1.2.3.4.5"
* @return The attribute syntax in dotted-decimal format.
*/
public String getSyntaxString() {
return syntaxElement.syntaxString;
}
/**
* Prepares a value in RFC 2252 format for submission to a server
*
* @param quotingBug <CODE>true</CODE> if SUP and SYNTAX values are to
* be quoted. This is required to work with bugs in certain LDAP servers.
* @return a String ready for submission to an LDAP server.
*/
String getValue( boolean quotingBug ) {
String s = getValuePrefix();
String val = getValue( SUPERIOR, false );
if ( val.length() > 0 ) {
s += val + ' ';
}
val = getOptionalValues( MATCHING_RULES );
if ( val.length() > 0 ) {
s += val + ' ';
}
val = getValue( SYNTAX, quotingBug );
if ( val.length() > 0 ) {
s += val + ' ';
}
if ( isSingleValued() ) {
s += SINGLE + ' ';
}
val = getOptionalValues( NOVALS );
if ( val.length() > 0 ) {
s += val + ' ';
}
val = getOptionalValues( new String[] {USAGE} );
if ( val.length() > 0 ) {
s += val + ' ';
}
val = getCustomValues();
if ( val.length() > 0 ) {
s += val + ' ';
}
s += ')';
return s;
}
/**
* Determines if the attribute type is collective
*
* @return <code>true</code> if collective
*/
public boolean isCollective() {
return (properties != null) ? properties.containsKey( COLLECTIVE ) :
false;
}
/**
* Determines if the attribute type is single-valued
*
* @return <code>true</code> if single-valued,
* <code>false</code> if multi-valued.
*/
public boolean isSingleValued() {
return (properties != null) ? properties.containsKey( SINGLE ) :
false;
}
/**
* Determines if the attribute type is modifiable by users
*
* @return <code>true</code> if modifiable by users
*/
public boolean isUserModifiable() {
return (properties != null) ?
!properties.containsKey( NO_USER_MODIFICATION ) :
true;
}
/**
* Gets the definition of the attribute type in Directory format
*
* @return definition of the attribute type in Directory format
*/
public String toString() {
return getValue( false );
}
/**
* Gets the attribute name for a schema element
*
* @return The attribute name of the element
*/
String getAttributeName() {
return "attributetypes";
}
// Predefined qualifiers
public static final String EQUALITY = "EQUALITY";
public static final String ORDERING = "ORDERING";
public static final String SUBSTR = "SUBSTR";
public static final String SINGLE = "SINGLE-VALUE";
public static final String COLLECTIVE = "COLLECTIVE";
public static final String NO_USER_MODIFICATION = "NO-USER-MODIFICATION";
public static final String USAGE = "USAGE";
// Usage constants
/** An ordinary user attribute
*/
public static final int USER_APPLICATIONS = 0;
/** An operational attribute used for a directory operation or which
* holds a directory specific value
*/
public static final int DIRECTORY_OPERATION = 1;
/** An operational attribute used to hold server (DSA) information that
* is shared among servers holding replicas of the entry
*/
public static final int DISTRIBUTED_OPERATION = 2;
/** An operational attribute used to hold server (DSA) information that
* is local to a server
*/
public static final int DSA_OPERATION = 3;
// Qualifiers known to not have values; prepare a Hashtable
static String[] NOVALS = { SINGLE,
COLLECTIVE,
NO_USER_MODIFICATION };
static {
for( int i = 0; i < NOVALS.length; i++ ) {
novalsTable.put( NOVALS[i], NOVALS[i] );
}
}
static final String[] MATCHING_RULES = { EQUALITY,
ORDERING,
SUBSTR };
// Qualifiers which we output explicitly in toString()
static final String[] IGNOREVALS = { SINGLE,
OBSOLETE,
SUPERIOR,
SINGLE,
COLLECTIVE,
NO_USER_MODIFICATION,
SYNTAX};
protected LDAPSyntaxSchemaElement syntaxElement =
new LDAPSyntaxSchemaElement();
}

View File

@@ -0,0 +1,618 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.io.Serializable;
import java.util.*;
import org.ietf.ldap.client.*;
import org.ietf.ldap.client.opers.*;
/**
* Represents a set of attributes (for example, the set of attributes
* in an entry).
*
* @version 1.0
* @see org.ietf.ldap.LDAPAttribute
*/
public class LDAPAttributeSet implements Cloneable, Serializable, Set {
static final long serialVersionUID = 5018474561697778100L;
HashMap _attrHash = null;
LDAPAttribute[] _attrs = new LDAPAttribute[0];
/* If there are less attributes than this in the set, it's not worth
creating a Hashtable - faster and cheaper most likely to do string
comparisons. Most applications fetch attributes once only, anyway */
static final int ATTR_COUNT_REQUIRES_HASH = 5;
/**
* Constructs a new set of attributes. This set is initially empty.
*/
public LDAPAttributeSet() {
// For now, always create the hashtable
prepareHashtable( true );
}
/**
* Constructs an attribute set.
* @param attrs the list of attributes
*/
public LDAPAttributeSet( LDAPAttribute[] attrs ) {
this();
if ( attrs == null ) {
attrs = new LDAPAttribute[0];
}
_attrs = attrs;
if ( _attrs.length > 0 ) {
for( int i = 0; i < _attrs.length; i++ ) {
add( _attrs[i] );
}
}
}
/**
* Removes all mappings from this attribute set
*/
public void clear() {
_attrHash = null;
if ( _attrs.length > 0 ) {
_attrs = new LDAPAttribute[0];
}
}
/**
* Adds the specified attribute to this attribute set, overriding
* any previous definition with the same attribute name
*
* @param attr attribute to add to this set
* @return true if this set changed as a result of the call
*/
public synchronized boolean add( Object attr ) {
if ( attr instanceof LDAPAttribute ) {
if ( contains( attr ) ) {
return false;
}
LDAPAttribute attrib = (LDAPAttribute)attr;
LDAPAttribute[] vals = new LDAPAttribute[_attrs.length+1];
for ( int i = 0; i < _attrs.length; i++ ) {
vals[i] = _attrs[i];
}
vals[_attrs.length] = attrib;
_attrs = vals;
if ( _attrHash != null ) {
_attrHash.put( attrib.getName().toLowerCase(), attr );
}
return true;
} else {
throw new ClassCastException( "Requires LDAPAttribute");
}
}
/**
* Adds the collection of attributes to this attribute set, overriding
* any previous definition with the same attribute names
*
* @param attrs attributes to add to this set
* @return true if any attribute was added
*/
public synchronized boolean addAll( Collection attrs ) {
if ( attrs == null ) {
return false;
}
boolean present = true;
Iterator it = attrs.iterator();
while( it.hasNext() ) {
Object attr = it.next();
if ( !contains( attr ) ) {
present = true;
add( attr );
}
}
return !present;
}
/**
* Returns a deep copy of this attribute set
*
* @return a deep copy of this attribute set
*/
public synchronized Object clone() {
try {
LDAPAttributeSet attributeSet = new LDAPAttributeSet();
attributeSet._attrs = new LDAPAttribute[_attrs.length];
for (int i = 0; i < _attrs.length; i++) {
attributeSet._attrs[i] = new LDAPAttribute(_attrs[i]);
}
return attributeSet;
} catch (Exception e) {
return null;
}
}
/**
* Returns true if this attribute set contains the specified attribute
*
* @param attr attribute whose presence in this set is to be tested
* @return true if the attribute set contains the specified attribute
*/
public boolean contains( Object attr ) {
if ( !(attr instanceof LDAPAttribute) ) {
return false;
} else {
if ( _attrHash != null ) {
return _attrHash.containsValue( attr );
} else {
for ( int i = 0; i < _attrs.length; i++ ) {
if ( attr.equals(_attrs[i]) ) {
return true;
}
}
}
return false;
}
}
/**
* Returns true if this attribute set contains all the specified attributes
*
* @param attrs attributes whose presence in this set is to be tested
* @return true if the attribute set contains the specified attributes
*/
public boolean containsAll( Collection attrs ) {
if ( _attrHash != null ) {
Iterator it = attrs.iterator();
while( it.hasNext() ) {
if ( !_attrHash.containsValue( it.next() ) ) {
return false;
}
}
return true;
} else {
return false;
}
}
/**
* Returns true if this attribute set contains the specified attribute name
*
* @param attrName attribute name whose presence in this set is to be tested
* @return true if the attribute set contains the specified attribute
*/
public boolean containsKey( Object attrName ) {
if ( !(attrName instanceof String) ) {
return false;
} else {
return ( getAttribute( (String)attrName ) != null );
}
}
/**
* Returns true if this attribute set equals a specified set
*
* @param attrSet attribute set to compare to
* @return true if this attribute set equals a specified set
*/
public boolean equals( Object attrSet ) {
if ( !(attrSet instanceof LDAPAttributeSet) ) {
return false;
}
return ((LDAPAttributeSet)attrSet)._attrHash.equals( _attrHash );
}
/**
* Returns the hash code for this attribute set
*
* @return the hash code for this attribute set
*/
public int hashCode() {
return _attrHash.hashCode();
}
/**
* Returns true if there are no attributes in this attribute set
*
* @return true if there are no attributes in this attribute set
*/
public boolean isEmpty() {
return ( _attrs.length < 1 );
}
/**
* Returns an iterator over the attributes in this attribute set
*
* @return an iterator over the attributes in this attribute set
*/
public Iterator iterator() {
return _attrHash.values().iterator();
}
/**
* Removes the specified attribute
*
* @param attr the attribute to remove
* @return true if the attribute was removed
*/
public boolean remove( Object attr ) {
if ( !(attr instanceof LDAPAttribute) ) {
return false;
}
boolean present = contains( attr );
if ( present ) {
synchronized(this) {
LDAPAttribute[] vals = new LDAPAttribute[_attrs.length-1];
int j = 0;
for (int i = 0; i < _attrs.length; i++) {
if ( !attr.equals(_attrs[i] ) ) {
vals[j++] = _attrs[i];
}
}
if (_attrHash != null) {
_attrHash.remove(
((LDAPAttribute)attr).getName().toLowerCase() );
}
_attrs = vals;
}
}
return present;
}
/**
* Removes the specified attributes
*
* @param attrs the attributes to remove
* @return true if any attribute was removed
*/
public boolean removeAll( Collection attrs ) {
if ( attrs == null ) {
return false;
}
boolean present = true;
Iterator it = attrs.iterator();
while( it.hasNext() ) {
Object attr = it.next();
if ( !contains( attr ) ) {
present = true;
remove( attr );
}
}
return !present;
}
/**
* Retains only the attributes in this set that are contained in the
* specified collection
*
* @param attrs attributes to retain
* @return true if the attribute set was changed as a result of the
* operation
*/
public boolean retainAll( Collection attrs ) {
HashMap newmap = new HashMap();
Iterator it = attrs.iterator();
while( it.hasNext() ) {
Object attr = it.next();
if ( attr instanceof LDAPAttribute ) {
newmap.put( ((LDAPAttribute)attr).getName().toLowerCase(),
attr );
}
}
if ( newmap.equals( _attrHash ) ) {
return false;
} else {
_attrHash = newmap;
_attrs = (LDAPAttribute[])_attrHash.values().toArray(
new LDAPAttribute[0] );
return true;
}
}
/**
* Returns the number of attributes in this set.
* @return number of attributes in this attribute set.
*/
public int size() {
return _attrs.length;
}
/**
* Returns the attributes of the set as an array
*
* @return the attributes of the set as an array
*/
public Object[] toArray() {
return _attrs;
}
/**
* Returns the attributes of the set as an array
*
* @param attrs an attribute array to fill with the attributes of this
* set. If the array is not large enough, a new array is allocated.
* @return the attributes of the set as an array
*/
public Object[] toArray( Object[] attrs ) {
if ( !(attrs instanceof LDAPAttribute[]) ) {
throw new ArrayStoreException(
"Must provide an LDAPAttribute array" );
} else if ( attrs.length >= _attrs.length ) {
for( int i = 0; i < _attrs.length; i++ ) {
attrs[i] = _attrs[i];
}
return attrs;
} else {
return _attrs;
}
}
/**
* Creates a new attribute set containing only the attributes
* that have the specified subtypes.
* <P>
*
* For example, suppose an attribute set contains the following attributes:
* <P>
*
* <PRE>
* cn
* cn;lang-ja
* sn;phonetic;lang-ja
* sn;lang-us
* </PRE>
*
* If you call the <CODE>getSubset</CODE> method and pass
* <CODE>lang-ja</CODE> as the argument, the method returns
* an attribute set containing the following attributes:
* <P>
*
* <PRE>
* cn;lang-ja
* sn;phonetic;lang-ja
* </PRE>
*
* @param subtype semi-colon delimited list of subtypes
* to find within attribute names.
* For example:
* <PRE>
* "lang-ja" // Only Japanese language subtypes
* "binary" // Only binary subtypes
* "binary;lang-ja" // Only Japanese language subtypes
* which also are binary
* </PRE>
* @return attribute set containing the attributes that have
* the specified subtypes.
* @see org.ietf.ldap.LDAPAttribute
* @see org.ietf.ldap.LDAPAttributeSet#getAttribute
* @see org.ietf.ldap.LDAPEntry#getAttributeSet
*/
public LDAPAttributeSet getSubset( String subtype ) {
LDAPAttributeSet attrs = new LDAPAttributeSet();
if ( subtype == null )
return attrs;
StringTokenizer st = new StringTokenizer(subtype, ";");
if( st.countTokens() < 1 )
return attrs;
String[] searchTypes = new String[st.countTokens()];
int i = 0;
while( st.hasMoreTokens() ) {
searchTypes[i] = (String)st.nextToken();
i++;
}
Iterator it = _attrHash.values().iterator();
while( it.hasNext() ) {
LDAPAttribute attr = (LDAPAttribute)it.next();
if( attr.hasSubtypes( searchTypes ) )
attrs.add( new LDAPAttribute( attr ) );
}
return attrs;
}
/**
* Returns a single attribute that exactly matches the specified attribute
* name.
* @param attrName name of attribute to return
* For example:
*<PRE>
* "cn" // Only a non-subtyped version of cn
* "cn;lang-ja" // Only a Japanese version of cn
*</PRE>
* @return attribute that has exactly the same name, or null
* (if no attribute in the set matches the specified name).
* @see org.ietf.ldap.LDAPAttribute
*/
public LDAPAttribute getAttribute( String attrName ) {
if ( attrName == null ) {
return null;
} else if ( _attrHash != null ) {
return (LDAPAttribute)_attrHash.get( attrName.toLowerCase() );
} else {
for ( int i = 0; i < _attrs.length; i++ ) {
if ( attrName.equalsIgnoreCase(_attrs[i].getName()) ) {
return _attrs[i];
}
}
return null;
}
}
/**
* Prepares hashtable for fast attribute lookups.
*/
private void prepareHashtable( boolean force ) {
if ( (_attrHash == null) &&
(force || (_attrs.length >= ATTR_COUNT_REQUIRES_HASH)) ) {
if ( _attrHash == null ) {
_attrHash = new HashMap();
} else {
_attrHash.clear();
}
for ( int j = 0; j < _attrs.length; j++ ) {
_attrHash.put( _attrs[j].getName().toLowerCase(), _attrs[j] );
}
}
}
/**
* Returns the subtype that matches the attribute name specified
* by <CODE>attrName</CODE> and the language specificaton identified
* by <CODE>lang</CODE>.
* <P>
*
* If no attribute in the set has the specified name and subtype,
* the method returns <CODE>null</CODE>.
*
* Attributes containing subtypes other than <CODE>lang</CODE>
* (for example, <CODE>cn;binary</CODE>) are returned only if
* they contain the specified <CODE>lang</CODE> subtype and if
* the set contains no attribute having only the <CODE>lang</CODE>
* subtype. (For example, <CODE>getAttribute( "cn", "lang-ja" )</CODE>
* returns <CODE>cn;lang-ja;phonetic</CODE> only if the
* <CODE>cn;lang-ja</CODE> attribute does not exist.)
* <P>
*
* If null is specified for the <CODE>lang</CODE> argument,
* calling this method is the same as calling the
* <CODE>getAttribute(attrName)</CODE> method.
* <P>
*
* For example, suppose an entry contains only the following attributes:
* <P>
* <UL>
* <LI><CODE>cn;lang-en</CODE>
* <LI><CODE>cn;lang-ja-JP-kanji</CODE>
* <LI><CODE>sn</CODE>
* </UL>
* <P>
*
* Calling the following methods will return the following values:
* <P>
* <UL>
* <LI><CODE>getAttribute( "cn" )</CODE> returns <CODE>null</CODE>.
* <LI><CODE>getAttribute( "sn" )</CODE> returns the "<CODE>sn</CODE>" attribute.
* <LI><CODE>getAttribute( "cn", "lang-en-us" )</CODE> returns the "<CODE>cn;lang-en</CODE>" attribute.
* <LI><CODE>getAttribute( "cn", "lang-en" )</CODE> returns the "<CODE>cn;lang-en</CODE>" attribute.
* <LI><CODE>getAttribute( "cn", "lang-ja" )</CODE> returns <CODE>null</CODE>.
* <LI><CODE>getAttribute( "sn", "lang-en" )</CODE> returns the "<CODE>sn</CODE>" attribute.
*</UL>
* <P>
* @param attrName name of attribute to find in the entry
* @param lang a language specification
* @return the attribute that matches the base name and that best
* matches any specified language subtype.
* @see org.ietf.ldap.LDAPAttribute
*/
public LDAPAttribute getAttribute( String attrName, String lang ) {
if ( (lang == null) || (lang.length() < 1) )
return getAttribute( attrName );
String langLower = lang.toLowerCase();
if ((langLower.length() < 5) ||
( !langLower.substring( 0, 5 ).equals( "lang-" ) )) {
return null;
}
StringTokenizer st = new StringTokenizer( langLower, "-" );
// Skip first token, which is "lang-"
st.nextToken();
String[] langComponents = new String[st.countTokens()];
int i = 0;
while ( st.hasMoreTokens() ) {
langComponents[i] = st.nextToken();
i++;
}
String searchBasename = LDAPAttribute.getBaseName(attrName);
String[] searchTypes = LDAPAttribute.getSubtypes(attrName);
LDAPAttribute found = null;
int matchCount = 0;
for( i = 0; i < _attrs.length; i++ ) {
boolean isCandidate = false;
LDAPAttribute attr = _attrs[i];
// Same base name?
if ( attr.getBaseName().equalsIgnoreCase(searchBasename) ) {
// Accept any subtypes?
if( (searchTypes == null) || (searchTypes.length < 1) ) {
isCandidate = true;
} else {
// No, have to check each subtype for inclusion
if( attr.hasSubtypes( searchTypes ) )
isCandidate = true;
}
}
String attrLang = null;
if ( isCandidate ) {
attrLang = attr.getLangSubtype();
// At this point, the base name and subtypes are okay
if ( attrLang == null ) {
// If there are no language attributes, this one is okay
found = attr;
} else {
// We just have to check for language match
st = new StringTokenizer( attrLang.toLowerCase(), "-" );
// Skip first token, which is "lang-"
st.nextToken();
// No match if the attribute's language spec is longer
// than the target one
if ( st.countTokens() > langComponents.length )
continue;
// How many subcomponents of the language match?
int j = 0;
while ( st.hasMoreTokens() ) {
if ( !langComponents[j].equals( st.nextToken() ) ) {
j = 0;
break;
}
j++;
}
if ( j > matchCount ) {
found = attr;
matchCount = j;
}
}
}
}
return found;
}
/**
* Retrieves the string representation of all attributes
* in the attribute set. For example:
*
* <PRE>
* LDAPAttributeSet: LDAPAttribute {type='cn', values='Barbara Jensen,Babs
* Jensen'}LDAPAttribute {type='sn', values='Jensen'}LDAPAttribute {type='
* givenname', values='Barbara'}LDAPAttribute {type='objectclass', values=
* 'top,person,organizationalPerson,inetOrgPerson'}LDAPAttribute {type='ou',
* values='Product Development,People'}
* </PRE>
*
* @return string representation of all attributes in the set.
*/
public String toString() {
StringBuffer sb = new StringBuffer("LDAPAttributeSet: ");
for( int i = 0; i < _attrs.length; i++ ) {
if (i != 0) {
sb.append(" ");
}
sb.append(_attrs[i].toString());
}
return sb.toString();
}
}

View File

@@ -0,0 +1,75 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
/**
* Specifies how to retrieve authentication information automatically
* for referrals. If you have set up the search constraints (or the options
* in the <CODE>LDAPConnection</CODE> object) to use automatic referral,
* you must define a class that implements this interface.
* <P>
*
* If no class implements this interface, clients that follow automatic
* referrals are authenticated anonymously to subsequent LDAP servers.
* The following example is a simple class that implements this interface.
* Objects of the myLDAPAuthHandler class check the host and port of the
* referred LDAP server. If the host and port are "alway.mcom.com:389",
* the directory manager's name and password are used to authenticate.
* For all other LDAP servers, anonymous authentication is used.
*
* <PRE>
* public class myLDAPAuthHandler implements org.ietf.ldap.LDAPAuthHandler
* {
* private String myDN;
* private String myPW;
* private LDAPAuthHandlerAuth myRebindInfo;
* public myLDAPAuthHandler () {
* myDN = "c=Directory Manager,o=Universal Exports,c=UK";
* myPW = "alway4444";
* }
*
* public LDAPAuthHandlerAuth getRebindAuthentication( String host, int port ) {
* if ( host.equalsIgnoreCase( "alway.mcom.com" ) && ( port == 389 ) ) {
* myRebindInfo = new LDAPAuthHandlerAuth( myDN, myPW );
* } else {
* myRebindInfo = new LDAPAuthHandlerAuth( "", "" );
* }
* return myRebindInfo;
* }
* } </PRE>
*
*
* @version 1.0
*/
public interface LDAPAuthHandler extends LDAPReferralHandler {
/**
* Returns an <CODE>LDAPAuthProvider</CODE> object, which the calling function
* can use to get the DN and password to use for authentication (if the client
* is set up to follow referrals automatically).
* @return LDAPAuthProvider object containing authentication information.
* @see org.ietf.ldap.LDAPAuthProvider
*/
public LDAPAuthProvider getAuthProvider( String host,
int port );
}

View File

@@ -0,0 +1,95 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.io.Serializable;
/**
* Represents information used to authenticate the client in cases where
* the client follows referrals automatically. If you are defining a class
* that implements the <CODE>LDAPRebind</CODE> interface, your implementation
* of the <CODE>LDAPRebind.getRebindAuthentication</CODE> method needs to
* construct and return an object of this class.
* <P>
*
* For example, the following method sets up authentication information based
* on the LDAP server identified in the referral. Ideally, this method would be
* defined as part of a class implementing the <CODE>LDAPRebind</CODE> interface.
*
* <PRE>
* private String myDN = "cn=Directory Manager,o=Ace Industry,c=US";
* private String myPW = "alway4444";
* private LDAPAuthProvider myRebindInfo;
* ...
* public LDAPAuthProvider getRebindAuthentication( String host, int port ) {
* if ( host.equalsIgnoreCase( "alway.mcom.com" ) && ( port == 389 ) ) {
* myRebindInfo = new LDAPAuthProvider( myDN, myPW );
* } else {
* myRebindInfo = new LDAPAuthProvider( "", "" );
* }
* return myRebindInfo;
* } </PRE>
*
* @version 1.0
* @see org.ietf.ldap.LDAPAuthHandler
*/
public class LDAPAuthProvider implements Serializable {
static final long serialVersionUID = 7161655313564756294L;
private String _dn;
private byte[] _password;
/**
* Constructs information that is used by the client
* for authentication when following referrals automatically.
* @param dn distinguished name to use for authenticating to
* the LDAP server during an automatic referral (if the client
* is set up to follow referrals automatically)
* @param password password to use for authenticating to
* the LDAP server during an automatic referral (if the client
* is set up to follow referrals automatically)
*/
public LDAPAuthProvider( String dn, byte[] password ) {
_dn = dn;
_password = password;
}
/**
* Returns the distinguished name to be used for reauthentication,
* if the client is set up to follow referrals automatically.
* @return distinguished name to use when authenticating to
* other LDAP servers during referrals.
*/
public String getDN() {
return _dn;
}
/**
* Returns the password to be used for reauthentication,
* if the client is set up to follow referrals automatically.
* @return password to use when authenticating to other
* LDAP servers during referrals.
*/
public byte[] getPassword() {
return _password;
}
}

View File

@@ -0,0 +1,50 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
/**
* Performs explicit bind processing on a referral. A client may
* specify an instance of this class for use on a single operation
* (through the <CODE>LDAPConstraints</CODE> object) or all operations
* (through <CODE>LDAPConnection.setOption()</CODE>). It is typically used
* to control the authentication mechanism used on implicit referral
* handling.
*/
public interface LDAPBindHandler {
/**
* This method is called by <CODE>LDAPConnection</CODE> when
* authenticating. An implementation of <CODE>LDAPBindHandler</CODE> may access
* the host, port, credentials, and other information in the
* <CODE>LDAPConnection</CODE> in order to decide on an appropriate
* authentication mechanism.<BR>
* The bind method can also interact with a user or external module.
* @exception org.ietf.ldap.LDAPReferralException
* @see org.ietf.ldap.LDAPConnection#bind
* @param ldapurls urls which may be selected to connect and bind to
* @param conn an established connection to an LDAP server
*/
public void bind( String[] ldapurls,
LDAPConnection conn ) throws LDAPReferralException;
}

View File

@@ -0,0 +1,819 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
import java.io.*;
import org.ietf.ldap.client.*;
import org.ietf.ldap.util.*;
import java.util.zip.CRC32;
/**
* <CODE>LDAPCache</CODE> represents an in-memory cache that you can use
* to reduce the number of search requests sent to the LDAP server.
* <P>
*
* Each item in the cache represents a search request and
* its results. Each item is uniquely identified by the
* search criteria, which includes:
* <P>
*
* <UL>
* <LI>the host name and port number of the LDAP server
* <LI>the base DN of the search
* <LI>the search filter
* <LI>the scope of the search
* <LI>the attributes to be returned in the search results
* <LI>the DN used to authenticate the client when binding
* to the server
* <LI>the LDAP v3 controls specified in the search request
* </UL>
* <P>
*
* After a search request is cached, the results of any
* subsequent search requests using the same criteria are
* read from the cache. Note that if any part of the
* criteria differs (for example, if a different DN is used
* when binding to the server or if a different set of
* attributes to be returned is specified), the search
* request is sent to the server.
* <P>
*
* When you create the cache, you specify the maximum amount
* of time that an item can be kept in the cache. When an
* item's age exceeds that time limit, the item is removed
* from the cache.
* <P>
*
* The cache also has a maximum size that you specify when
* creating the cache. If adding a new item exceeds the
* maximum size of the cache, the first entries in the cache
* are removed to make enough space for the new item.
* <P>
*
* Finally, when creating the cache, you can specify a list
* of the base DNs in search requests that you want to cache.
* For example, if you specify <CODE>o=Airius.com</CODE> as
* a base DN to cache, your client caches search requests
* where the base DN is <CODE>o=Airius.com</CODE>.
* <P>
*
* To specify that you want to use a cache for a particular
* LDAP session, call the <CODE>setCache</CODE> method of
* the <CODE>LDAPConnection</CODE> object that you are
* working with.
* <P>
*
* All clones of an <CODE>LDAPConnection</CODE> object share
* the same <CODE>LDAPCache</CODE> object.
* <P>
*
* Note that <CODE>LDAPCache</CODE> does not maintain consistency
* with the directory, so that cached search results may no longer be
* valid after a directory update. If the same application is performing
* both cached searches and directory updates, then the
* application should flush the corresponding cache entries after an update.
* To do this use the <CODE>flushEntries</CODE> method.
* <P>
*
* Also, note that search requests that return referrals are not cached.
* <P>
*
* The <CODE>LDAPCache</CODE> class includes methods for
* getting statistics (such as hit rates) from the cache and
* for flushing entries from the cache.
* <P>
*
* @see org.ietf.ldap.LDAPConnection#setCache(org.ietf.ldap.LDAPCache)
* @see org.ietf.ldap.LDAPConnection#getCache
*/
public class LDAPCache implements Serializable {
static final long serialVersionUID = 6275167993337814294L;
/**
* A hashtable of search results. The key is created from the search
* request parameters (see createKey() method). The value is a Vector
* where the first element is a Long integer representing the size
* of all entries, followed by the actual search result entries (of type
* LDAPEntry).
*/
private Hashtable m_cache;
/**
* A list of cached entries ordered by time (augments m_cache). Each
* element in the list is a 2 element Vector where the element at index
* 0 is the key in the m_cache table, and the element at index 1 is the
* time when the entry was created.
* The list is used to track the time-to-live limit and to implement the
* FIFO algorithm when adding new entries; if the size of the new entry
* exceeds the cache available space, the extra space is made by removing
* existing cached results in the order of their entry in the cache.
*/
private Vector m_orderedStruct;
private long m_timeToLive;
private long m_maxSize;
private String[] m_dns;
private long m_remainingSize = 0;
// Count of LDAPConnections that share this cache
private int m_refCnt = 0;
/**
* Delimiter used internally when creating keys
* for the cache.
*/
public static final String DELIM = "#";
private TTLTimer m_timer = null;
private long m_totalOpers = 0;
private long m_hits = 0;
private long m_flushes = 0;
// Debug can be activated by defining debug.cache property
private static boolean m_debug = false;
static {
try {
String traceProp = System.getProperty("debug.cache");
m_debug = (traceProp != null);
}
catch (Exception e) {
;// In browser access to property might not be allowed
}
}
/**
* Constructs a new <CODE>LDAPCache</CODE> object, using the
* specified maximum size of the cache (in bytes) and the maximum
* age of cached items (in seconds). When items in the cache
* exceed this age, they are removed from the cache.
* <P>
*
* @param ttl the maximum amount of time that an item can be cached
* (in seconds)
* @param size the maximum size of the cache (in bytes)
*/
public LDAPCache(long ttl, long size)
{
init(ttl, size);
}
/**
* Constructs a new <CODE>LDAPCache</CODE> object, using the
* specified maximum size of the cache (in bytes), and the maximum
* age of cached items (in seconds), and an array of the base DNs
* of searches that you want to cache. (For example,
* if the array of base DNs includes <CODE>o=Airius.com</CODE>,
* the cache stores search results if the base DN in the search
* request is <CODE>o=Airius.com</CODE>.)
* <P>
*
* @param ttl the maximum amount of time that an item can be cached
* (in seconds)
* @param size the maximum size of the cache (in bytes)
* @param dns the list of base DNs of searches that you want to cache.
*/
public LDAPCache(long ttl, long size, String[] dns)
{
init(ttl, size);
m_dns = new String[dns.length];
if ((dns != null) && (dns.length > 0))
for (int i=0; i<dns.length; i++) {
m_dns[i] = (new DN(dns[i])).toString();
}
}
/**
* Gets the maximum size of the cache (in bytes).
* <P>
*
* @return the maximum size of the cache (in bytes).
*/
public long getSize()
{
return m_maxSize;
}
/**
* Gets the maximum age allowed for cached items (in
* seconds). (Items that exceed this age are
* removed from the cache.)
* <P>
*
* @return the maximum age of items in the cache (in
* seconds).
*/
public long getTimeToLive()
{
return m_timeToLive/1000;
}
/**
* Gets the array of base DNs of searches to be cached.
* (Search requests with these base DNs are cached.)
* <P>
*
* @return the array of base DNs.
*/
public String[] getBaseDNs()
{
return m_dns;
}
/**
* Flush the entries identified by DN and scope from the cache.
* <P>
*
* @param dn the distinguished name (or base DN) of the entries
* to be removed from the cache. Use this parameter in conjunction
* with <CODE>scope</CODE> to identify the entries that you want
* removed from the cache. If this parameter is <CODE>null</CODE>,
* the entire cache is flushed.
* @param scope the scope identifying the entries that you want
* removed from the cache. The value of this parameter can be
* one of the following:
* <UL>
* <LI><CODE>LDAPConnection.SCOPE_BASE</CODE> (to remove the entry identified
* by <CODE>dn</CODE>)
* <LI><CODE>LDAPConnection.SCOPE_ONE</CODE> (to remove the entries that
* have <CODE>dn</CODE> as their parent entry)
* <LI><CODE>LDAPConnection.SCOPE_SUB</CODE> (to remove the entries in the
* subtree under <CODE>dn</CODE> in the directory)
* </UL>
* <P>
* @return <CODE>true</CODE> if the entry is removed from the cache;
* <CODE>false</CODE> if the entry is not removed.
*/
public synchronized boolean flushEntries(String dn, int scope) {
if (m_debug)
System.out.println("DEBUG: User request for flushing entry: dn "+
dn+" and scope "+scope);
// if the dn is null, invalidate the whole cache
if (dn == null)
{
// reclaim all the cache spaces
m_remainingSize = m_maxSize;
m_cache.clear();
m_orderedStruct.removeAllElements();
// reset stats
m_totalOpers = m_hits = m_flushes = 0;
return true;
}
DN dn2 = new DN(dn);
Enumeration e = m_cache.keys();
while(e.hasMoreElements()) {
Long key = (Long)e.nextElement();
Vector val = (Vector)m_cache.get(key);
// LDAPEntries start at idx 1, at idx 0 is a Long
// (size of all LDAPEntries returned by search())
int j=1;
int size2=val.size();
for (; j<size2; j++) {
String d = ((LDAPEntry)val.elementAt(j)).getDN();
DN dn1 = new DN(d);
if (dn1.equals(dn2))
break;
if (scope == LDAPConnection.SCOPE_ONE) {
DN parentDN1 = dn1.getParent();
if (parentDN1.equals(dn2)) {
break;
}
}
if ((scope == LDAPConnection.SCOPE_SUB) &&
(dn1.isDescendantOf(dn2))) {
break;
}
}
if (j < size2) {
for (int k=0; k<m_orderedStruct.size(); k++) {
Vector v = (Vector)m_orderedStruct.elementAt(k);
if (key.equals((Long)v.elementAt(0))) {
m_orderedStruct.removeElementAt(k);
break;
}
}
Vector entry = (Vector)m_cache.remove(key);
m_remainingSize += ((Long)entry.firstElement()).longValue();
if (m_debug)
System.out.println("DEBUG: Successfully removed entry ->"+key);
return true;
}
}
if (m_debug)
System.out.println("DEBUG: The number of keys in the cache is "
+m_cache.size());
return false;
}
/**
* Gets the amount of available space (in bytes) left in the cache.
* <P>
*
* @return the available space (in bytes) in the cache.
*/
public long getAvailableSize() {
return m_remainingSize;
}
/**
* Gets the total number of requests for retrieving items from
* the cache. This includes both items successfully found in
* the cache and items not found in the cache.
* <P>
*
* @return the total number of requests for retrieving items from
* the cache.
*/
public long getTotalOperations() {
return m_totalOpers;
}
/**
* Gets the total number of requests which failed to find and
* retrieve an item from the cache.
* <P>
*
* @return the number of requests that did not find and retrieve
* an item in the cache.
*/
public long getNumMisses() {
return (m_totalOpers - m_hits);
}
/**
* Gets the total number of requests which successfully found and
* retrieved an item from the cache.
* @return the number of requests that successfully found and
* retrieved an item from the cache.
*/
public long getNumHits() {
return m_hits;
}
/**
* Gets the total number of entries that are flushed when timer expires
* and <CODE>flushEntries</CODE> is called.
* <P>
*
* @return the total number of entries that are flushed when timer
* expires.
*/
public long getNumFlushes() {
return m_flushes;
}
/**
* Create a key for a cache entry by concatenating all input parameters
* @return the key for a cache entry
* @exception LDAPException Thrown when failed to create key.
*/
Long createKey(String host, int port, String baseDN, String filter,
int scope, String[] attrs, String bindDN, LDAPConstraints cons)
throws LDAPException {
DN dn = new DN(baseDN);
baseDN = dn.toString();
if (m_dns != null) {
int i=0;
for (; i<m_dns.length; i++) {
if (baseDN.equals(m_dns[i]))
break;
}
if (i >= m_dns.length)
throw new LDAPException(baseDN+" is not a cached base DN",
LDAPException.OTHER);
}
String key = null;
key = appendString(baseDN);
key = key+appendString(scope);
key = key+appendString(host);
key = key+appendString(port);
key = key+appendString(filter);
key = key+appendString(attrs);
key = key+appendString(bindDN);
LDAPControl[] serverControls = null;
// get server and client controls
if (cons != null) {
serverControls = cons.getControls();
}
if ((serverControls != null) && (serverControls.length > 0)) {
String[] objID = new String[serverControls.length];
for (int i=0; i<serverControls.length; i++) {
LDAPControl ctrl = serverControls[i];
long val = getCRC32(ctrl.getValue());
objID[i] = ctrl.getID() + ctrl.isCritical() +
new Long(val).toString();
}
key = key + appendString(objID);
} else {
key = key+appendString(0);
}
long val = getCRC32(key.getBytes());
if ( m_debug ) {
System.out.println("key="+val + " for "+key);
}
return new Long(val);
}
/**
* Gets the cache entry based on the specified key.
* @param key the key for the cache entry
* @return the cache entry.
*/
synchronized Object getEntry(Long key) {
Object obj = null;
obj = m_cache.get(key);
m_totalOpers++;
if (m_debug) {
if (obj == null)
System.out.println("DEBUG: Entry whose key -> "+key+
" not found in the cache.");
else
System.out.println("DEBUG: Entry whose key -> "+key+
" found in the cache.");
}
if (obj != null)
m_hits++;
return obj;
}
/**
* Flush entries which stay longer or equal to the time-to-live.
*/
synchronized void flushEntries()
{
Vector v = null;
boolean delete = false;
long currTime = System.currentTimeMillis();
m_flushes = 0;
while(true) {
if (m_orderedStruct.size() <= 0)
break;
v = (Vector)m_orderedStruct.firstElement();
long diff = currTime-((Long)v.elementAt(1)).longValue();
if (diff >= m_timeToLive) {
Long key = (Long)v.elementAt(0);
if (m_debug)
System.out.println("DEBUG: Timer flush entry whose key is "+key);
Vector entry = (Vector)m_cache.remove(key);
m_remainingSize += ((Long)entry.firstElement()).longValue();
// always delete the first one
m_orderedStruct.removeElementAt(0);
m_flushes++;
}
else
break;
}
if (m_debug)
System.out.println("DEBUG: The number of keys in the cache is "
+m_cache.size());
}
/**
* Add the entry to the hashtable cache and to the vector respectively.
* The vector is used to keep track of the order of the entries being added.
* @param key the key for the cache entry
* @param value the cache entry being added to the cache for the specified
* key
* @return a flag indicating whether the entry was added.
*/
synchronized boolean addEntry(Long key, Object value)
{
// if entry exists, dont perform add operation
if (m_cache.get(key) != null)
return false;
Vector v = (Vector)value;
long size = ((Long)v.elementAt(0)).longValue();
if (size > m_maxSize) {
if (m_debug) {
System.out.println("Failed to add an entry to the cache since the new entry exceeds the cache size");
}
return false;
}
// if the size of entry being added is bigger than the spare space in the
// cache
if (size > m_remainingSize) {
while (true) {
Vector element = (Vector)m_orderedStruct.firstElement();
Long str = (Long)element.elementAt(0);
Vector val = (Vector)m_cache.remove(str);
if (m_debug)
System.out.println("DEBUG: The spare size of the cache is not big enough "+
"to hold the new entry, deleting the entry whose key -> "+str);
// always remove the first one
m_orderedStruct.removeElementAt(0);
m_remainingSize += ((Long)val.elementAt(0)).longValue();
if (m_remainingSize >= size)
break;
}
}
m_remainingSize -= size;
m_cache.put(key, v);
Vector element = new Vector(2);
element.addElement(key);
element.addElement(new Long(System.currentTimeMillis()));
m_orderedStruct.addElement(element);
// Start TTL Timer if first entry is added
if (m_orderedStruct.size() == 1) {
scheduleTTLTimer();
}
if (m_debug)
{
System.out.println("DEBUG: Adding a new entry whose key -> "+key);
System.out.println("DEBUG: The current number of keys in the cache "+
m_cache.size());
}
return true;
}
/**
* Flush entries which stayed longer or equal to the time-to-live, and
* Set up the TTLTimer for the next flush. Called when first entry is
* added to the cache and when the TTLTimer expires.
*/
synchronized void scheduleTTLTimer() {
if (m_orderedStruct.size() <= 0) {
return;
}
if (m_timer == null) {
m_timer = new TTLTimer(this);
}
Vector v = (Vector)m_orderedStruct.firstElement();
long currTime = System.currentTimeMillis();
long creationTime = ((Long)v.elementAt(1)).longValue();
long timeout = creationTime + m_timeToLive - currTime;
if (timeout > 0) {
m_timer.start(timeout);
}
else {
flushEntries();
scheduleTTLTimer();
}
}
/**
* Gets the number of entries being cached.
* @return the number of entries being cached.
*/
public int getNumEntries()
{
return m_cache.size();
}
/**
* Get number of LDAPConnections that share this cache
* @return Reference Count
*/
int getRefCount() {
return m_refCnt;
}
/**
* Add a new reference to this cache.
*
*/
synchronized void addReference() {
m_refCnt++;
if (m_debug) {
System.err.println("Cache refCnt="+ m_refCnt);
}
}
/**
* Remove a reference to this cache.
* If the reference count is 0, cleaup the cache.
*
*/
synchronized void removeReference() {
if (m_refCnt > 0) {
m_refCnt--;
if (m_debug) {
System.err.println("Cache refCnt="+ m_refCnt);
}
if (m_refCnt == 0 ) {
cleanup();
}
}
}
/**
* Cleans up
*/
synchronized void cleanup() {
flushEntries(null, 0);
if (m_timer != null) {
m_timer.stop();
m_timer = null;
}
}
/**
* Initialize the instance variables.
*/
private void init(long ttl, long size)
{
m_cache = new Hashtable();
m_timeToLive = ttl*1000;
m_maxSize = size;
m_remainingSize = size;
m_dns = null;
m_orderedStruct = new Vector();
}
/**
* Concatenates the specified integer with the delimiter.
* @param str the String to concatenate with the delimiter
* @return the concatenated string.
*/
private String appendString(String str) {
if (str == null)
return "null"+DELIM;
else
return str.trim()+DELIM;
}
/**
* Concatenates the specified integer with the delimiter.
* @param num the integer to concatenate with the delimiter
* @return the concatenated string.
*/
private String appendString(int num) {
return num+DELIM;
}
/**
* Concatenate the specified string array with the delimiter.
* @param str a string array
* @return the concatenated string.
*/
private String appendString(String[] str) {
if ((str == null) || (str.length < 1))
return "0"+DELIM;
else {
String[] sorted = new String[str.length];
System.arraycopy( str, 0, sorted, 0, str.length );
sortStrings(sorted);
String s = sorted.length+DELIM;
for (int i=0; i<sorted.length; i++)
s = s+sorted[i].trim()+DELIM;
return s;
}
}
/**
* Sorts the array of strings using bubble sort.
* @param str the array of strings to sort. The str parameter contains
* the sorted result.
*/
private void sortStrings(String[] str) {
for (int i=0; i<str.length; i++)
str[i] = str[i].trim();
for (int i=0; i<str.length-1; i++)
for (int j=i+1; j<str.length; j++)
{
if (str[i].compareTo(str[j]) > 0)
{
String t = str[i];
str[i] = str[j];
str[j] = t;
}
}
}
/**
* Create a 32 bits CRC from the given byte array.
*/
private long getCRC32(byte[] barray) {
if (barray==null) {
return 0;
}
CRC32 crcVal = new CRC32();
crcVal.update(barray);
return crcVal.getValue();
}
}
/**
* Represents a timer which will timeout for every certain interval. It
* provides methods to start, stop, or restart timer.
*/
class TTLTimer implements Runnable{
private long m_timeout;
private LDAPCache m_cache;
private Thread t = null;
/**
* Constructor with the specified timout.
* @param timeout the timeout value in milliseconds
*/
TTLTimer(LDAPCache cache) {
m_cache = cache;
}
/**
* (Re)start the timer.
*/
void start(long timeout) {
m_timeout = timeout;
if (Thread.currentThread() != t) {
stop();
}
t = new Thread(this, "LDAPCache-TTLTimer");
t.setDaemon(true);
t.start();
}
/**
* Stop the timer.
*/
void stop() {
if (t !=null) {
t.interrupt();
}
}
/**
* The runnable waits until the timeout period has elapsed. It then notify
* the registered listener who listens for the timeout event.
*/
public void run() {
synchronized(this) {
try {
this.wait(m_timeout);
} catch (InterruptedException e) {
// This happens if the timer is stopped
return;
}
}
m_cache.scheduleTTLTimer();
}
}

View File

@@ -0,0 +1,66 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
/**
* This static class checks if the caller is an applet running in
* Netscape Communicator. If so, it returns the appropriate method.
*/
class LDAPCheckComm {
/**
* Returns the method whose name matches the specified argument.
* @param classPackage the class package
* @param name the method name
* @return the method.
* @exception LDAPException Gets thrown if the method is not found or
* the caller is not an applet running in Netscape
* Communicator.
*/
static java.lang.reflect.Method getMethod(String classPackage, String name) throws LDAPException {
SecurityManager sec = System.getSecurityManager();
if ( sec == null ) {
/* Not an applet, we can do what we want to */
return null;
} else if ( sec.toString().startsWith("java.lang.NullSecurityManager") ) {
/* Not an applet, we can do what we want to */
return null;
} else if (sec.toString().startsWith("netscape.security.AppletSecurity")) {
/* Running as applet. Is PrivilegeManager around? */
try {
Class c = Class.forName(classPackage);
java.lang.reflect.Method[] m = c.getMethods();
for( int i = 0; i < m.length; i++ ) {
if ( m[i].getName().equals(name) ) {
return m[i];
}
}
throw new LDAPException("no enable privilege in " + classPackage);
} catch (ClassNotFoundException e) {
throw new LDAPException("Class not found");
}
}
return null;
}
}

View File

@@ -0,0 +1,337 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.io.Serializable;
import java.util.*;
import java.text.*;
/**
* Compares LDAP entries based on one or more attribute values.
* <P>
*
* To use this comparison for sorting search results, pass
* an object of this class to the <CODE>sort</CODE> method in
* <CODE>LDAPSearchResults</CODE>.
* <P>
*
* @version 1.0
* @see LDAPSearchResults#sort
*/
public class LDAPCompareAttrNames
implements Comparator, Serializable {
static final long serialVersionUID = -2567450425231175944L;
private String _attrs[];
private boolean _ascending[];
private Locale _locale = null;
private Collator _collator = null;
private boolean _sensitive = true;
/**
* Constructs a comparator that compares the string values of
* a named attribute in LDAP entries and sorts the entries in
* ascending order.
* <P>
*
* @param attribute name of attribute for comparisons
*/
public LDAPCompareAttrNames (String attribute) {
_attrs = new String[1];
_attrs[0] = attribute;
_ascending = new boolean[1];
_ascending[0] = true;
}
/**
* Constructs a comparator that compares the string values of
* a named attribute in LDAP entries and that allows you to sort
* entries either in ascending or descending order.
* <P>
*
* @param attribute name of attribute for comparisons
* @param ascendingFlag if <CODE>true</CODE>, sort in ascending order
*/
public LDAPCompareAttrNames (String attribute,
boolean ascendingFlag) {
_attrs = new String[1];
_attrs[0] = attribute;
_ascending = new boolean[1];
_ascending[0] = ascendingFlag;
}
/**
* Constructs a comparator that compares the string values of
* a set of named attributes in LDAP entries and that sort
* the entries in ascending order.
* <P>
*
* Use an array of strings to specify the set of attributes
* to use for sorting. If the values of the first attribute
* (the name specified in <CODE>attribute[0]</CODE>) are equal,
* then the values of the next attribute are compared.
* <P>
*
* For example, if <CODE>attributes[0] = "cn"</CODE> and
* <CODE>attributes[1]="uid"</CODE>, results are first sorted
* by the <CODE>cn</CODE> attribute. If two entries have the
* same value for <CODE>cn</CODE>, then the <CODE>uid</CODE>
* attribute is used to sort the entries.
* <P>
*
* @param attributes array of the attribute names used for comparisons
*/
public LDAPCompareAttrNames (String[] attributes) {
_attrs = attributes;
_ascending = new boolean[attributes.length];
for( int i = 0; i < attributes.length; i++ )
_ascending[i] = true;
}
/**
* Constructs a comparator that compares the string values of
* a set of named attributes in LDAP entries and allows you
* to sort the entries in ascending or descending order.
* <P>
*
* Use an array of strings to specify the set of attributes
* to use for sorting. If the values of the first attribute
* (the name specified in <CODE>attribute[0]</CODE>)
* are equal, then the values of the next attribute are compared.
* <P>
*
* For example, if <CODE>attributes[0] = "cn"</CODE> and
* <CODE>attributes[1]="uid"</CODE>, results are first sorted
* by the <CODE>cn</CODE> attribute. If two entries have the
* same value for <CODE>cn</CODE>, then the <CODE>uid</CODE>
* attribute is used to sort the entries.
* <P>
*
* Use an array of boolean values to specify whether each attribute
* should be sorted in ascending or descending order. For example,
* suppose that <CODE>attributes[0] = "cn"</CODE> and
* <CODE>attributes[1]="roomNumber"</CODE>. If
* <CODE>ascendingFlags[0]=true</CODE> and
* <CODE>ascendingFlags[1]=false</CODE>, attributes are sorted first by
* <CODE>cn</CODE> in ascending order, then by <CODE>roomNumber</CODE>
* in descending order.
* <P>
*
* If the size of the array of attribute names is not the same as
* the size of the array of boolean values, an
* <CODE>LDAPException</CODE> is thrown.
* <P>
*
* @param attribute array of the attribute names to use for comparisons
* @param ascendingFlags array of boolean values specifying ascending
* or descending order to use for each attribute name. If
* <CODE>true</CODE>, the attributes are sorted in ascending order.
*/
public LDAPCompareAttrNames (String[] attributes,
boolean[] ascendingFlags) {
_attrs = attributes;
_ascending = ascendingFlags;
if ( _ascending == null ) {
_ascending = new boolean[attributes.length];
for( int i = 0; i < attributes.length; i++ )
_ascending[i] = true;
}
}
/**
* Indicates if some other object is "equal to" this Comparator
*
* @param obj the object to compare
* @return true if the object equals this object
*/
public boolean equals( Object obj ) {
return super.equals( obj );
}
/**
* Gets the locale, if any, used for collation. If the locale is null,
* an ordinary string comparison is used for sorting.
*
* @return the locale used for collation, or null.
*/
public Locale getLocale() {
return _locale;
}
/**
* Set the locale, if any, used for collation. If the locale is null,
* an ordinary string comparison is used for sorting. If sorting
* has been set to case-insensitive, the collation strength is set
* to Collator.PRIMARY, otherwise to Collator.IDENTICAL. If a
* different collation strength setting is required, use the signature
* that takes a collation strength parameter.
*
* @param locale the locale used for collation, or null.
*/
public void setLocale( Locale locale ) {
if ( _sensitive ) {
setLocale( locale, Collator.IDENTICAL );
} else {
setLocale( locale, Collator.PRIMARY );
}
}
/**
* Sets the locale, if any, used for collation. If the locale is null,
* an ordinary string comparison is used for sorting.
*
* @param locale the locale used for collation, or null.
* @param strength collation strength: Collator.PRIMARY,
* Collator.SECONDARY, Collator.TERTIARY, or Collator.IDENTICAL
*/
public void setLocale( Locale locale, int strength ) {
_locale = locale;
if ( _locale == null ) {
_collator = null;
} else {
_collator = Collator.getInstance( _locale );
_collator.setStrength(strength);
}
}
/**
* Gets the state of the case-sensitivity flag. This only applies to
* Unicode sort order; for locale-specific sorting, case-sensitivity
* is controlled by the collation strength.
*
* @return <code>true</code> for case-sensitive sorting; this is
* the default
*/
public boolean getCaseSensitive() {
return _sensitive;
}
/**
* Sets the state of the case-sensitivity flag. This only applies to
* Unicode sort order; for locale-specific sorting, case-sensitivity
* is controlled by the collation strength.
*
* @param sensitive <code>true</code> for case-sensitive sorting;
* this is the default
*/
public void setCaseSensitive( boolean sensitive ) {
_sensitive = sensitive;
}
/**
* Compares its two arguments for order
*
* @param entry1 the first entry to be compared
* @param entry2 the second entry to be compared
* @return a negative integer, zero, or a positive integer if the first
* argument is less than, equal to, or greater than the second
* @exception ClassCastException if either of the arguments is not
* an LDAPEntry
*/
public int compare( Object entry1, Object entry2 ) {
if ( !(entry1 instanceof LDAPEntry) ||
!(entry2 instanceof LDAPEntry) ) {
throw new ClassCastException( "Must compare LDAPEntry objects" );
}
return attrGreater( (LDAPEntry)entry1, (LDAPEntry)entry2, 0 );
}
/**
* Compares a particular attribute in both entries. If equal,
* moves on to the next.
* @param entry1 the first entry to be compared
* @param entry2 the second entry to be compared
* @return a negative integer, zero, or a positive integer if the first
* argument is less than, equal to, or greater than the second
*/
int attrGreater( LDAPEntry entry1, LDAPEntry entry2,
int attrPos ) {
Iterator attrSet1 =
entry1.getAttributeSet().iterator();
Iterator attrSet2 =
entry2.getAttributeSet().iterator();
String value1 = null;
String value2 = null;
String attrName = _attrs[attrPos];
boolean ascending = _ascending[attrPos];
while ( attrSet2.hasNext() ) {
LDAPAttribute currAttr = (LDAPAttribute)(attrSet2.next());
if ( !attrName.equalsIgnoreCase (currAttr.getName()) ) {
continue;
}
value2 = (String)(currAttr.getStringValues().nextElement());
break;
}
while ( attrSet1.hasNext() ) {
LDAPAttribute currAttr = (LDAPAttribute)(attrSet1.next());
if ( !attrName.equalsIgnoreCase(currAttr.getName()) ) {
continue;
}
value1 = (String)(currAttr.getStringValues().nextElement());
break;
}
if ( (value2 == null) ^ (value1 == null) ) {
return (value1 != null) ? 1 : -1;
}
// Check for equality
if ( (value2 == null) ||
((_collator != null) &&
(_collator.compare( value1, value2 ) == 0) ) ||
((_collator == null) && _sensitive &&
value2.equals(value1)) ||
((_collator == null) && !_sensitive &&
value2.equalsIgnoreCase(value1)) ) {
if ( attrPos == _attrs.length - 1 ) {
return -1;
} else {
return attrGreater ( entry1, entry2, attrPos+1 );
}
}
// Not equal, check for order
if ( ascending ) {
if ( _collator != null ) {
return _collator.compare( value1, value2 );
} else if ( _sensitive ) {
return value1.compareTo( value2 );
} else {
return value1.toLowerCase().compareTo( value2.toLowerCase() );
}
} else {
if ( _collator != null ) {
return _collator.compare( value1, value2 );
} else if ( _sensitive ) {
return value1.compareTo( value2 );
} else {
return value1.toLowerCase().compareTo( value2.toLowerCase() );
}
}
}
}

View File

@@ -0,0 +1,542 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
import java.io.*;
import java.net.*;
/**
* Makes a connection to a server from a list using "smart" failover.
* Connection attempts can be made serially from the same thread, or
* in parallel by creating a separate thread after the specified delay.
* Connection setup status is preserved for later attempts, so that servers
* that are more likely to be available will be tried first.
* <P>
* The total time spent opening a connection can be limited with the
* <CODE>ConnectTimeout</CODE> property.
* <P>
* When a connection is successfully created, a socket is opened. The socket
* is passed to the LDAPConnThread. The LDAPConnThread must call
* invalidateConnection() if the connection is lost due to a network or
* server error, or disconnect() if the connection is deliberately terminated
* by the user.
*/
class LDAPConnSetupMgr implements Cloneable, Serializable {
static final long serialVersionUID = 1519402748245755306L;
/**
* Policy for opening a connection when multiple servers are used
*/
private static final int SERIAL = 0;
private static final int PARALLEL = 1;
/**
* ServerEntry.connSetupStatus possible value. The values also represent
* the likelihood that the connection will be setup to a server. Lower
* values have higher priority. See sortDsList() method
*/
private static final int CONNECTED = 0;
private static final int DISCONNECTED = 1;
private static final int NEVER_USED = 2;
private static final int INTERRUPTED = 3;
private static final int FAILED = 4;
/**
* Representation for a server in the server list.
*/
class ServerEntry {
String host;
int port;
int connSetupStatus;
Thread connSetupThread;
ServerEntry(String host, int port, int status) {
this.host = host;
this.port = port;
connSetupStatus = status;
connSetupThread = null;
}
public String toString() {
return "{" +host+":"+port + " status="+connSetupStatus+"}";
}
}
/**
* Socket to the connected server
*/
private Socket _socket = null;
/**
* Last exception occured during connection setup
*/
private LDAPException _connException = null;
/**
* List of server to use for the connection setup
*/
ServerEntry[] _dsList;
/**
* Index of the last connected server
*/
private int _dsIdx = -1;
/**
* Socket factory for SSL connections
*/
LDAPSocketFactory _factory;
/**
* Connection setup policy (PARALLEL or SERIAL)
*/
int _policy = SERIAL;
/**
* Delay in ms before another connection setup thread is started.
*/
int _connSetupDelay = -1;
/**
* The maximum time to wait to established the connection
*/
int _connectTimeout = 0;
/**
* During connection setup, the current count of servers to which
* connection attmpt has been made
*/
private transient int _attemptCnt = 0;
/**
* Connection IDs for ldap trace messages
*/
private static int _nextId;
private int _id;
/**
* Constructor
* @param host list of host names to which to connect
* @param port list of port numbers corresponding to the host list
* @param factory socket factory for SSL connections
*/
LDAPConnSetupMgr(String[] hosts, int[] ports, LDAPSocketFactory factory) {
_dsList = new ServerEntry[hosts.length];
for (int i=0; i < hosts.length; i++) {
_dsList[i] = new ServerEntry(hosts[i], ports[i], NEVER_USED);
}
_factory = factory;
_id = _nextId++;
}
/**
* Try to open the connection to any of the servers in the list, limiting
* the time waiting for the connection to be established
* @return connection socket
*/
synchronized Socket openConnection() throws LDAPException{
long tcur=0, tmax = Long.MAX_VALUE;
Thread th = null;
reset();
// If reconnecting, sort dsList so that servers more likly to
// be available are tried first
sortDsList();
if (_connectTimeout == 0) {
// No need for a separate thread, connect time not limited
connect();
}
else {
// Wait for connection at most _connectTimeout milliseconds
// Run connection setup in a separate thread to monitor the time
tmax = System.currentTimeMillis() + _connectTimeout;
th = new Thread (new Runnable() {
public void run() {
connect();
}
}, "ConnSetupMgr");
th.setDaemon(true);
th.start();
while (_socket==null && (_attemptCnt < _dsList.length) &&
(tcur = System.currentTimeMillis()) < tmax) {
try {
wait(tmax - tcur);
}
catch (InterruptedException e) {
th.interrupt();
cleanup();
throw new LDAPInterruptedException("Interrupted connect operation");
}
}
}
if (_socket != null) {
return _socket;
}
if ( th != null && (tcur = System.currentTimeMillis()) >= tmax) {
// We have timed out
th.interrupt();
cleanup();
throw new LDAPException(
"connect timeout, " + getServerList() + " might be unreachable",
LDAPException.CONNECT_ERROR);
}
if (_connException != null && _dsList.length == 1) {
throw _connException;
}
throw new LDAPException(
"failed to connect to server " + getServerList(),
LDAPException.CONNECT_ERROR);
}
private void reset() {
_socket = null;
_connException = null;
_attemptCnt = 0;
for (int i=0; i < _dsList.length; i++) {
_dsList[i].connSetupThread = null;
}
}
private String getServerList() {
StringBuffer sb = new StringBuffer();
for (int i=0; i < _dsList.length; i++) {
sb.append(i==0 ? "" : " ");
sb.append(_dsList[i].host);
sb.append(":");
sb.append(_dsList[i].port);
}
return sb.toString();
}
private void connect() {
if (_policy == SERIAL || _dsList.length == 1) {
openSerial();
}
else {
openParallel();
}
}
/**
* Called when the current connection is lost.
* Put the connected server at the end of the server list for
* the next connect attempt.
*/
synchronized void invalidateConnection() {
if (_socket != null) {
_dsList[_dsIdx].connSetupStatus = FAILED;
// Move the entry to the end of the list
int srvCnt = _dsList.length, j=0;
ServerEntry[] newDsList = new ServerEntry[_dsList.length];
for (int i=0; i < srvCnt; i++) {
if (i != _dsIdx) {
newDsList[j++] = _dsList[i];
}
}
newDsList[j] = _dsList[_dsIdx];
_dsList = newDsList;
_dsIdx = j;
}
_socket = null;
}
/**
* Called when the current connection is terminated by the user.
* Mark the connected server status as DISCONNECTED. This will
* put it at top of the server list for the next connect attempt.
*/
void disconnect() {
if (_socket != null) {
_dsList[_dsIdx].connSetupStatus = DISCONNECTED;
}
_socket = null;
}
Socket getSocket() {
return _socket;
}
String getHost() {
if (_dsIdx >= 0) {
return _dsList[_dsIdx].host;
}
return _dsList[0].host;
}
int getPort() {
if (_dsIdx >= 0) {
return _dsList[_dsIdx].port;
}
return _dsList[0].port;
}
int getConnSetupDelay() {
return _connSetupDelay/1000;
}
/**
* Selects the connection failover policy
* @param delay in seconds for the parallel connection setup policy.
* Possible values are: <br>(delay=-1) use serial policy,<br>
* (delay=0) start immediately concurrent threads to each specified server
* <br>(delay>0) create a new connection setup thread after delay seconds
*/
void setConnSetupDelay(int delay) {
_policy = (delay < 0) ? SERIAL : PARALLEL;
_connSetupDelay = delay*1000;
}
int getConnectTimeout() {
return _connectTimeout/1000;
}
/**
* Sets the maximum time to spend in the openConnection() call
* @param timeout in seconds to wait for the connection to be established
*/
void setConnectTimeout(int timeout) {
_connectTimeout = timeout*1000;
}
/**
* Check if the user has voluntarily closed the connection
*/
boolean isUserDisconnected() {
return (_dsIdx >=0 &&
_dsList[_dsIdx].connSetupStatus == DISCONNECTED);
}
/**
* Try sequentially to open a new connection to a server.
*/
private void openSerial() {
for (int i=0; i < _dsList.length; i++) {
_dsList[i].connSetupThread = Thread.currentThread();
connectServer(i);
if (_socket != null) {
return;
}
}
}
/**
* Try concurrently to open a new connection a server. Create a separate
* thread for each connection attempt.
*/
private synchronized void openParallel() {
for (int i=0; _socket==null && i < _dsList.length; i++) {
//Create a Thread to execute connectSetver()
final int dsIdx = i;
String threadName = "ConnSetupMgr " +
_dsList[dsIdx].host + ":" + _dsList[dsIdx].port;
Thread t = new Thread(new Runnable() {
public void run() {
connectServer(dsIdx);
}
}, threadName);
_dsList[dsIdx].connSetupThread = t;
t.setDaemon(true);
t.start();
// Wait before starting another thread if the delay is not zero
if (_connSetupDelay != 0 && i < (_dsList.length-1)) {
try {
wait(_connSetupDelay);
}
catch (InterruptedException e) {
return;
}
}
}
// At this point all threads are started. Wait until first thread
// succeeds to connect or all threads terminate
while (_socket == null && (_attemptCnt < _dsList.length)) {
// Wait for a thread to terminate
try {
wait();
}
catch (InterruptedException e) {}
}
}
/**
* Connect to the server at the given index
*/
void connectServer(int idx) {
ServerEntry entry = _dsList[idx];
Thread currThread = Thread.currentThread();
Socket sock = null;
LDAPException conex = null;
try {
/* If we are to create a socket ourselves, make sure it has
sufficient privileges to connect to the desired host */
if (_factory == null) {
sock = new Socket (entry.host, entry.port);
//s.setSoLinger( false, -1 );
} else {
sock = _factory.createSocket(entry.host, entry.port);
}
}
catch (IOException e) {
conex = new LDAPException("failed to connect to server "
+ entry.host+":"+entry.port, LDAPException.CONNECT_ERROR);
}
catch (LDAPException e) {
conex = e;
}
if (currThread.isInterrupted()) {
return;
}
synchronized (this) {
if (_socket == null && entry.connSetupThread == currThread) {
entry.connSetupThread = null;
if (sock != null) {
entry.connSetupStatus = CONNECTED;
_socket = sock;
_dsIdx = idx;
cleanup(); // Signal other concurrent threads to terminate
}
else {
entry.connSetupStatus = FAILED;
_connException = conex;
}
_attemptCnt++;
notifyAll();
}
}
}
/**
* Terminate all concurrently running connection setup threads
*/
private synchronized void cleanup() {
Thread currThread = Thread.currentThread();
for (int i=0; i < _dsList.length; i++) {
ServerEntry entry = _dsList[i];
if (entry.connSetupThread != null && entry.connSetupThread != currThread) {
entry.connSetupStatus = INTERRUPTED;
//Thread.stop() is considered to be dangerous, use Thread.interrupt().
//interrupt() will however not work if the thread is blocked in the
//socket library native connect() call, but the connect() will
//eventually timeout and the thread will die.
entry.connSetupThread.interrupt();
entry.connSetupThread = null;
}
}
}
/**
* Sorts Server List so that servers which are more likely to be available
* are tried first. The likelihood of making a successful connection
* is determined by the connSetupStatus. Lower values have higher
* likelihood. Thus, the order of server access is (1) disconnected by
* the user (2) never used (3) interrupted connection attempt
* (4) connection setup failed/connection lost
*/
private void sortDsList() {
int srvCnt = _dsList.length;
for (int i=1; i < srvCnt; i++) {
for (int j=0; j < i; j++) {
if (_dsList[i].connSetupStatus < _dsList[j].connSetupStatus) {
// swap entries
ServerEntry entry = _dsList[j];
_dsList[j] = _dsList[i];
_dsList[i] = entry;
}
}
}
}
/**
* This is used only by the ldapjdk test libaray to simulate a
* server problem and to test fail-over and rebind
* @return A flag whether the connection was closed
*/
boolean breakConnection() {
try {
_socket.close();
return true;
}
catch (Exception e) {
return false;
}
}
public String toString() {
String str = "dsIdx="+_dsIdx+ " dsList=";
for (int i=0; i < _dsList.length; i++) {
str += _dsList[i]+ " ";
}
return str;
}
int getID() {
return _id;
}
String getLDAPUrl() {
return ((_factory == null) ? "ldap" : "ldaps") +
"://" + getHost() + ":" + getPort();
}
public Object clone() {
try {
LDAPConnSetupMgr cloneMgr = (LDAPConnSetupMgr) super.clone();
cloneMgr._dsList = new ServerEntry[_dsList.length];
for (int i=0; i<_dsList.length; i++) {
ServerEntry e = _dsList[i];
cloneMgr._dsList[i] = new ServerEntry(e.host, e.port, e.connSetupStatus);
}
return cloneMgr;
}
catch (CloneNotSupportedException ex) {
return null;
}
}
}

View File

@@ -0,0 +1,721 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
import org.ietf.ldap.client.*;
import org.ietf.ldap.client.opers.*;
import org.ietf.ldap.ber.stream.*;
import org.ietf.ldap.util.*;
import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
/**
* Multiple LDAPConnection clones can share a single physical connection,
* which is maintained by a thread.
*
* +----------------+
* | LDAPConnection | --------+
* +----------------+ |
* |
* +----------------+ | +----------------+
* | LDAPConnection | --------+------- | LDAPConnThread |
* +----------------+ | +----------------+
* |
* +----------------+ |
* | LDAPConnection | --------+
* +----------------+
*
* All LDAPConnections send requests and get responses from
* LDAPConnThread (a thread).
*/
class LDAPConnThread extends Thread {
/**
* Constants
*/
private final static int MAXMSGID = Integer.MAX_VALUE;
private final static int BACKLOG_CHKCNT = 50;
/**
* Internal variables
*/
transient private static int _highMsgId;
transient private InputStream _serverInput;
transient private OutputStream _serverOutput;
transient private Hashtable _requests;
transient private Hashtable _messages = null;
transient private Vector _registered;
transient private boolean _disconnected = false;
transient private LDAPCache _cache = null;
transient private boolean _doRun = true;
private Socket _socket = null;
transient private Thread _thread = null;
transient Object _sendRequestLock = new Object();
transient LDAPConnSetupMgr _connMgr = null;
transient Object _traceOutput = null;
transient private int _backlogCheckCounter = BACKLOG_CHKCNT;
// Time Stamp format Hour(0-23):Minute:Second.Milliseconds used for
// trace msgs
static SimpleDateFormat _timeFormat =
new SimpleDateFormat( "HH:mm:ss.SSS" );
/**
* Constructs a connection thread that maintains connection to the
* LDAP server
*
* @param connMgr
* @param cache
* @param traceOutput
*/
public LDAPConnThread( LDAPConnSetupMgr connMgr,
LDAPCache cache,
Object traceOutput )
throws LDAPException {
super( "LDAPConnThread " + connMgr.getHost() +
":" + connMgr.getPort() );
_requests = new Hashtable ();
_registered = new Vector ();
_connMgr = connMgr;
_socket = connMgr.getSocket();
setCache( cache );
setTraceOutput( traceOutput );
// Allow the application to exit if only LDAPConnThread threads are
// running
setDaemon( true );
try {
_serverInput =
new BufferedInputStream( _socket.getInputStream() );
_serverOutput =
new BufferedOutputStream( _socket.getOutputStream() );
} catch ( IOException e ) {
// a kludge to make the thread go away. Since the thread has already
// been created, the only way to clean up the thread is to call the
// start() method. Otherwise, the exit method will be never called
// because the start() was never called. In the run method, stop
// is called right away if _doRun is false.
_doRun = false;
start();
throw new LDAPException ( "failed to connect to server " +
_connMgr.getHost(),
LDAPException.CONNECT_ERROR );
}
if ( traceOutput != null ) {
StringBuffer sb = new StringBuffer( " connected to " );
sb.append( _connMgr.getLDAPUrl() );
logTraceMessage( sb );
}
start(); /* start the thread */
}
InputStream getInputStream() {
return _serverInput;
}
void setInputStream( InputStream is ) {
_serverInput = is;
}
OutputStream getOutputStream() {
return _serverOutput;
}
void setOutputStream( OutputStream os ) {
_serverOutput = os;
}
void setTraceOutput( Object traceOutput ) {
synchronized ( _sendRequestLock ) {
if ( traceOutput == null ) {
_traceOutput = null;
} else if ( traceOutput instanceof OutputStream ) {
_traceOutput = new PrintWriter( (OutputStream)traceOutput );
} else if ( traceOutput instanceof LDAPTraceWriter ) {
_traceOutput = traceOutput;
}
}
}
void logTraceMessage( StringBuffer msg ) {
if ( _traceOutput == null ) {
return;
}
String timeStamp = _timeFormat.format( new Date() );
StringBuffer sb = new StringBuffer( timeStamp );
sb.append( " ldc=" );
sb.append( _connMgr.getID() );
synchronized( _sendRequestLock ) {
if ( _traceOutput instanceof PrintWriter ) {
PrintWriter traceOutput = (PrintWriter)_traceOutput;
traceOutput.print( sb ); // header
traceOutput.println( msg );
traceOutput.flush();
} else if ( _traceOutput instanceof LDAPTraceWriter ) {
sb.append( msg );
((LDAPTraceWriter)_traceOutput).write( sb.toString() );
}
}
}
/**
* Set the cache to use for searches.
* @param cache The cache to use for searches; <CODE>null</CODE> for no
* cache
*/
synchronized void setCache( LDAPCache cache ) {
_cache = cache;
_messages = (_cache != null) ? new Hashtable() : null;
}
/**
* Allocates a new LDAP message ID. These are arbitrary numbers used to
* correlate client requests with server responses.
*
* @return new unique msgId
*/
private int allocateId() {
synchronized( _sendRequestLock ) {
_highMsgId = (_highMsgId + 1) % MAXMSGID;
return _highMsgId;
}
}
/**
* Sends an LDAP request via this connection thread
*
* @param request request to send
* @param toNotify response queue to receive the response
* when ready
*/
void sendRequest( LDAPConnection conn, JDAPProtocolOp request,
LDAPMessageQueue toNotify, LDAPConstraints cons )
throws LDAPException {
if ( !_doRun ) {
throw new LDAPException ( "not connected to a server",
LDAPException.SERVER_DOWN );
}
LDAPMessage msg =
new LDAPMessage( allocateId(), request, cons.getControls() );
LDAPMessageQueueImpl queue = (LDAPMessageQueueImpl)toNotify;
if ( queue != null ) {
if ( !(request instanceof JDAPAbandonRequest ||
request instanceof JDAPUnbindRequest) ) {
/* Only worry about toNotify if we expect a response... */
this._requests.put( new Integer( msg.getMessageID()),
queue );
/* Notify the backlog checker that there may be another
outstanding request */
resultRetrieved();
}
queue.addRequest( msg.getMessageID(), conn, this,
cons.getTimeLimit() );
}
synchronized( _sendRequestLock ) {
try {
if ( _traceOutput != null ) {
logTraceMessage( msg.toTraceString() );
}
msg.write( _serverOutput );
_serverOutput.flush();
} catch ( IOException e ) {
networkError( e );
}
}
}
/**
* Registers with this connection thread
*
* @param conn LDAP connection
*/
public synchronized void register( LDAPConnection conn ) {
if ( !_registered.contains( conn ) )
_registered.addElement( conn );
}
int getClientCount() {
return _registered.size();
}
boolean isRunning() {
return _doRun;
}
/**
* Deregisters with this connection thread. If all connections
* are deregistered, this thread is to be killed.
*
* @param conn LDAP connection
*/
public synchronized void deregister(LDAPConnection conn) {
_registered.removeElement( conn );
if ( _registered.size() == 0 ) {
try {
if ( !_disconnected ) {
LDAPSearchConstraints cons = conn.getSearchConstraints();
sendRequest( null, new JDAPUnbindRequest(), null, cons );
}
// must be set after the call to sendRequest
_doRun =false;
if ( (_thread != null) &&
(_thread != Thread.currentThread()) ) {
_thread.interrupt();
// Wait up to 1 sec for thread to accept disconnect
// notification. When the interrupt is accepted,
// _thread is set to null. See run() method.
try {
wait( 1000 );
}
catch ( InterruptedException e ) {
}
}
} catch( Exception e ) {
LDAPConnection.printDebug( e.toString() );
}
finally {
cleanUp();
}
}
}
/**
* Cleans up before shutting down the thread
*/
private void cleanUp() {
if ( !_disconnected ) {
try {
_serverOutput.close();
} catch ( Exception e ) {
} finally {
_serverOutput = null;
}
try {
_serverInput.close ();
} catch ( Exception e ) {
} finally {
_serverInput = null;
}
try {
_socket.close ();
} catch ( Exception e ) {
} finally {
_socket = null;
}
_disconnected = true;
/**
* Notify the Connection Setup Manager that the connection was
* terminated by the user
*/
_connMgr.disconnect();
/**
* Cancel all outstanding requests
*/
if ( _requests != null ) {
Enumeration requests = _requests.elements();
while ( requests.hasMoreElements() ) {
LDAPMessageQueueImpl queue =
(LDAPMessageQueueImpl)requests.nextElement();
queue.removeAllRequests( this );
}
}
/**
* Notify all the registered queues of this mishap.
* IMPORTANT: This needs to be done last. Otherwise, the socket
* input stream and output stream might never get closed and the
* whole task will get stuck when trying to stop the
* LDAPConnThread.
*/
if ( _registered != null ) {
Vector registerCopy = (Vector)_registered.clone();
Enumeration cancelled = registerCopy.elements();
while ( cancelled.hasMoreElements() ) {
LDAPConnection c = (LDAPConnection)cancelled.nextElement();
c.deregisterConnection();
}
}
_registered.clear();
_registered = null;
_messages = null;
_requests.clear();
_cache = null;
}
}
/**
* Sleep if there is a backlog of search results
*/
private void checkBacklog() throws InterruptedException{
while ( true ) {
if ( _requests.size() == 0 ) {
return;
}
Enumeration queues = _requests.elements();
while( queues.hasMoreElements() ) {
LDAPMessageQueue l = (LDAPMessageQueue)queues.nextElement();
// If there are any threads waiting for a regular response
// message, we have to go read the next incoming message
if ( !(l instanceof LDAPSearchQueue ) ) {
return;
}
LDAPSearchQueue sl = (LDAPSearchQueue)l;
// should never happen, but just in case
if ( sl.getSearchConstraints() == null ) {
return;
}
int slMaxBacklog = sl.getSearchConstraints().getMaxBacklog();
int slBatchSize = sl.getSearchConstraints().getBatchSize();
// Disabled backlog check ?
if ( slMaxBacklog == 0 ) {
return;
}
// Synch op with zero batch size ?
if ( !sl.isAsynchOp() && slBatchSize == 0 ) {
return;
}
// Max backlog not reached for at least one queue ?
// (if multiple requests are in progress)
if ( sl.getMessageCount() < slMaxBacklog ) {
return;
}
}
synchronized( this ) {
wait( 3000 );
}
}
}
/**
* This is called when a search result has been retrieved from the incoming
* queue. We use the notification to unblock the queue thread, if it
* is waiting for the backlog to lighten.
*/
synchronized void resultRetrieved() {
notifyAll();
}
/**
* Reads from the LDAP server input stream for incoming LDAP messages.
*/
public void run() {
// if there is a problem establishing a connection to the server,
// stop the thread right away...
if ( !_doRun ) {
return;
}
_thread = Thread.currentThread();
LDAPMessage msg = null;
JDAPBERTagDecoder decoder = new JDAPBERTagDecoder();
while ( _doRun ) {
yield();
int[] nread = new int[1];
nread[0] = 0;
try {
// Check after every BACKLOG_CHKCNT number of messages if the
// backlog is too high
if ( --_backlogCheckCounter <= 0 ) {
_backlogCheckCounter = BACKLOG_CHKCNT;
checkBacklog();
}
BERElement element = BERElement.getElement( decoder,
_serverInput,
nread );
msg = LDAPMessage.parseMessage( element );
if ( _traceOutput != null ) {
logTraceMessage( msg.toTraceString() );
}
// pass in the ber element size to approximate the size of the
// cache entry, thereby avoiding serialization of the entry
// stored in the cache
processResponse( msg, nread[0] );
} catch ( Exception e ) {
if (_doRun) {
networkError( e );
} else {
// interrupted from deregister()
synchronized( this ) {
_thread = null;
notifyAll();
}
}
}
}
}
/**
* When a response arrives from the LDAP server, it is processed by
* this routine. It will pass the message on to the listening object
* associated with the LDAP msgId.
* @param msg New message from LDAP server
*/
private void processResponse( LDAPMessage msg, int size ) {
Integer messageID = new Integer( msg.getMessageID() );
LDAPMessageQueueImpl l =
(LDAPMessageQueueImpl)_requests.get( messageID );
if ( l == null ) {
return; /* nobody is waiting for this response (!) */
}
// For asynch operations controls are to be read from the LDAPMessage
// For synch operations controls are copied into the LDAPConnection
// For synch search operations, controls are also copied into
// LDAPSearchResults (see LDAPConnection.checkSearchMsg())
if ( ! l.isAsynchOp() ) {
/* Were there any controls for this client? */
LDAPControl[] con = msg.getControls();
if ( con != null ) {
int msgid = msg.getMessageID();
LDAPConnection ldc = l.getConnection( msgid );
if ( ldc != null ) {
ldc.setResponseControls(
this, new LDAPResponseControl(ldc, msgid, con) );
}
}
}
if ( (_cache != null) && (l instanceof LDAPSearchQueue) ) {
cacheSearchResult( (LDAPSearchQueue)l, msg, size );
}
l.addMessage( msg );
if ( msg instanceof LDAPResponse ) {
_requests.remove( messageID );
if ( _requests.size() == 0 ) {
_backlogCheckCounter = BACKLOG_CHKCNT;
}
}
}
/**
* Collects search results to be added to the LDAPCache. Search results are
* packaged in a vector and temporary stored into a hashtable _messages
* using the message id as the key. The vector first element (at index 0)
* is a Long integer representing the total size of all LDAPEntries entries.
* It is followed by the actual LDAPEntries.
* If the total size of entries exceeds the LDAPCache max size, or a
* referral has been received, caching of search results is disabled and
* the entry is not added to the LDAPCache. A disabled search request is
* denoted by setting the entry size to -1.
*/
private synchronized void cacheSearchResult( LDAPSearchQueue l,
LDAPMessage msg, int size ) {
Integer messageID = new Integer( msg.getMessageID() );
Long key = l.getKey();
Vector v = null;
if ( (_cache == null) || (key == null) ) {
return;
}
if ( msg instanceof LDAPSearchResult ) {
// Get the vector containing the LDAPMessages for the specified
// messageID
v = (Vector)_messages.get( messageID );
if ( v == null ) {
_messages.put( messageID, v = new Vector() );
v.addElement( new Long(0) );
}
// Return if the entry size is -1, i.e. caching is disabled
if ( ((Long)v.firstElement()).longValue() == -1L ) {
return;
}
// add the size of the current LDAPMessage to the lump sum
// assume the size of LDAPMessage is more or less the same as
// the size of LDAPEntry. Eventually an LDAPEntry object gets
// stored in the cache instead of the LDAPMessage object.
long entrySize = ((Long)v.firstElement()).longValue() + size;
// If the entrySize exceeds the cache size, discard the collected
// entries and disble collecting of entries for this search request
// by setting the entry size to -1.
if ( entrySize > _cache.getSize() ) {
v.removeAllElements();
v.addElement( new Long(-1L) );
return;
}
// update the lump sum located in the first element of the vector
v.setElementAt( new Long(entrySize), 0 );
// convert LDAPMessage object into LDAPEntry which is stored to the
// end of the Vector
v.addElement( ((LDAPSearchResult)msg).getEntry() );
} else if ( msg instanceof LDAPSearchResultReference ) {
// If a search reference is received disable caching of
// this search request
v = (Vector)_messages.get(messageID);
if ( v == null ) {
_messages.put( messageID, v = new Vector() );
}
else {
v.removeAllElements();
}
v.addElement( new Long(-1L) );
} else if ( msg instanceof LDAPResponse ) {
// The search request has completed. Store the cache entry
// in the LDAPCache if the operation has succeded and caching
// is not disabled due to the entry size or referrals
boolean fail = ((LDAPResponse)msg).getResultCode() > 0;
v = (Vector)_messages.remove( messageID );
if ( !fail ) {
// If v is null, meaning there are no search results from the
// server
if ( v == null ) {
v = new Vector();
v.addElement(new Long(0));
}
// add the new entry if the entry size is not -1 (caching
// disabled)
if ( ((Long)v.firstElement()).longValue() != -1L ) {
_cache.addEntry( key, v );
}
}
}
}
/**
* Stop dispatching responses for a particular message ID
*
* @param id Message ID for which to discard responses
*/
void abandon( int id ) {
if ( !_doRun ) {
return;
}
LDAPMessageQueueImpl l =
(LDAPMessageQueueImpl)_requests.remove( new Integer(id) );
// Clean up cache if enabled
if ( _messages != null ) {
_messages.remove( new Integer(id) );
}
if ( l != null ) {
l.removeRequest( id );
}
resultRetrieved(); // If LDAPConnThread is blocked in checkBacklog()
}
/**
* Changes the queue for a message ID. Required when
* LDAPMessageQueue.merge() is invoked.
*
* @param id Message ID for which to change the queue
* @return Previous queue
*/
LDAPMessageQueue changeQueue( int id, LDAPMessageQueue toNotify ) {
if ( !_doRun ) {
LDAPMessageQueueImpl queue = (LDAPMessageQueueImpl)toNotify;
queue.setException( this,
new LDAPException( "Server down",
LDAPException.OTHER ) );
return null;
}
return (LDAPMessageQueue)_requests.put( new Integer(id), toNotify );
}
/**
* Handles network errors. Basically shuts down the whole connection.
*
* @param e The exception which was caught while trying to read from
* input stream.
*/
private synchronized void networkError( Exception e ) {
_doRun = false;
// notify the Connection Setup Manager that the connection is lost
_connMgr.invalidateConnection();
try {
// notify each queue that the server is down.
Enumeration requests = _requests.elements();
while ( requests.hasMoreElements() ) {
LDAPMessageQueueImpl queue =
(LDAPMessageQueueImpl)requests.nextElement();
queue.setException( this,
new LDAPException( "Server down",
LDAPException.OTHER) );
}
} catch( NullPointerException ee ) {
System.err.println( "Exception: " + ee.toString() );
}
cleanUp();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,299 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.io.Serializable;
import java.util.Hashtable;
/**
* Represents a set of operation preferences.
* You can set these preferences for a particular operation
* by creating an <CODE>LDAPConstraints</CODE> object,
* specifying your preferences, and passing the object to
* the proper <CODE>LDAPConnection</CODE> method.
* <P>
*
* @version 1.0
*/
public class LDAPConstraints implements Cloneable, Serializable {
static final long serialVersionUID = 6506767263918312029L;
private int _hop_limit = 5;
private LDAPReferralHandler _referralHandler = null;
private boolean referrals = false;
private int _time_limit = 0;
private LDAPControl[] _serverControls = null;
private Hashtable _properties = null;
/**
* Constructs an <CODE>LDAPConstraints</CODE> object that specifies
* the default set of constraints.
*/
public LDAPConstraints() {
}
/**
* Constructs a new <CODE>LDAPConstraints</CODE> object and allows you
* to specify the constraints in that object.
* <P>
* @param msLimit maximum time in milliseconds to wait for results (0
* by default, which means that there is no maximum time limit)
* @param doReferrals specify <CODE>true</CODE> to follow referrals
* automatically, or <CODE>False</CODE> to throw an
* <CODE>LDAPReferralException</CODE> error if the server sends back
* a referral (<CODE>False</CODE> by default)
* @param handler specifies the object that
* implements the <CODE>LDAPReferralHandler</CODE> interface (you need to
* define this class). The object will be used when the client
* follows referrals automatically. See org.ietf.ldap.LDAPAuthHandler
* and org.ietf.ldap.LDAPReferralHandler.
* (This field is <CODE>null</CODE> by default.)
* @param hop_limit maximum number of referrals to follow in a
* sequence when attempting to resolve a request
* @see org.ietf.ldap.LDAPConnection#setOption(int, java.lang.Object)
*/
public LDAPConstraints( int msLimit, boolean doReferrals,
LDAPReferralHandler handler,
int hop_limit ) {
_time_limit = msLimit;
referrals = doReferrals;
_referralHandler = handler;
_hop_limit = hop_limit;
_serverControls = null;
}
/**
* Returns the maximum number of milliseconds to wait for any operation
* under these constraints. If 0, there is no maximum time limit
* on waiting for the operation results.
* @return maximum number of milliseconds to wait for operation results.
*/
public int getTimeLimit() {
return _time_limit;
}
/**
* Specifies whether nor not referrals are followed automatically.
* Returns <CODE>true</CODE> if referrals are to be followed automatically,
* or <CODE>false</CODE> if referrals throw an
* <CODE>LDAPReferralException</CODE>.
* @return <CODE>true</CODE> if referrals are followed automatically,
* <CODE>false</CODE> if referrals throw an
* <CODE>LDAPReferralException</CODE>.
*/
public boolean getReferralFollowing() {
return referrals;
}
/**
* Returns the object that provides the mechanism for authenticating to the
* server on referrals. This object must implement the
* <CODE>LDAPReferralHandler</CODE> interface.
* @return object to use to authenticate to the server on referrals
* @see org.ietf.ldap.LDAPReferralHandler
*/
public LDAPReferralHandler getReferralHandler() {
return _referralHandler;
}
/**
* Returns the maximum number of hops to follow during a referral.
* @return maximum number of hops to follow during a referral.
*/
public int getHopLimit() {
return _hop_limit;
}
/**
* Returns any server controls to be applied by the server
* to LDAP operations.
* @return server controls for the server to apply to LDAP operations.
* @see org.ietf.ldap.LDAPControl
* @see org.ietf.ldap.LDAPConnection#getOption
* @see org.ietf.ldap.LDAPConnection#setOption
*/
public LDAPControl[] getControls() {
return _serverControls;
}
/**
* Gets a property of a constraints object which has been assigned with
* setProperty. Null is returned if the property is not defined.
*
* @param name Name of the property to retrieve
*/
public Object getProperty( String name ) {
if ( _properties == null ) {
return null;
}
return _properties.get( name );
}
/**
* Sets the maximum number of milliseconds to wait for any operation
* under these constraints. If 0, there is no maximum time limit
* on waiting for the operation results. If the time limit is exceeded,
* an LDAPException with the result code <CODE>LDAPException.TIME_LIMIT
* </CODE> is thrown.
* @param msLimit Maximum number of milliseconds to wait for operation
* results (0 by default, which means that there is no maximum time
* limit.)
* @see org.ietf.ldap.LDAPException#LDAP_TIMEOUT
*/
public void setTimeLimit( int msLimit ) {
_time_limit = msLimit;
}
/**
* Specifies whether or not referrals are followed automatically.
* Specify <CODE>true</CODE> if referrals are to be followed automatically,
* or <CODE>false</CODE> if referrals are to throw an
* <CODE>LDAPReferralException</CODE>.
* (By default, this is set to <CODE>false</CODE>.)
* <P>
* If you set this to <CODE>true</CODE>, you need to create an object of
* this class that implements either the <CODE>LDAPAuthHandler</CODE> or
* <CODE>LDAPBind</CODE> interface. The <CODE>LDAPAuthProvider</CODE> object
* identifies the method for retrieving authentication information which
* will be used when connecting to other LDAP servers during referrals.
* This object should be passed to the <CODE>setReferralHandler</CODE> method.
* Alternatively, the <CODE>LDAPBind</CODE> object identifies an
* authentication mechanism to be used instead of the default
* authentication mechanism when following referrals. This
* object should be passed to the <CODE>setBindHandler</CODE> method.
* @param doReferrals set to <CODE>true</CODE> if referrals should be
* followed automatically, or <CODE>False</CODE> if referrals should throw
* an <CODE>LDAPReferralException</CODE>
* @see org.ietf.ldap.LDAPBindHandler
* @see org.ietf.ldap.LDAPAuthHandler
* @see org.ietf.ldap.LDAPAuthProvider
*/
public void setReferralFollowing( boolean doReferrals ) {
referrals = doReferrals;
}
/**
* Specifies the object that provides the method for getting
* authentication information. This object must belong to a class
* that implements the <CODE>LDAPReferralHandler</CODE> interface.
* (By default, this is <CODE>null</CODE>.) This method sets the
* <CODE>LDAPReferralHandler</CODE> object to null for this constraint.
* @param handler object to use to obtain information for
* authenticating to other LDAP servers during referrals
*/
public void setReferralHandler( LDAPReferralHandler handler ) {
_referralHandler = handler;
}
/**
* Sets maximum number of hops to follow in sequence during a referral.
* (By default, this is 5.)
* @param hop_limit maximum number of hops to follow during a referral
*/
public void setHopLimit( int hop_limit ) {
_hop_limit = hop_limit;
}
/**
* Sets a server control for LDAP operations.
* @param control server control for LDAP operations
* @see org.ietf.ldap.LDAPControl
*/
public void setControls( LDAPControl control ) {
_serverControls = new LDAPControl[1];
_serverControls[0] = control;
}
/**
* Sets an array of server controls for LDAP operations.
* @param controls an array of server controls for LDAP operations
* @see org.ietf.ldap.LDAPControl
*/
public void setControls( LDAPControl[] controls ) {
_serverControls = controls;
}
/**
* Sets a property of the constraints object.
* No property names have been defined at this time, but the mechanism
* is in place in order to support revisional as well as dynamic and
* proprietary extensions to operation modifiers.
*
* @param name Name of the property to set
* @param value Value to assign to the property
*/
public void setProperty( String name, Object value ) throws LDAPException {
if ( _properties == null ) {
_properties = new Hashtable();
}
_properties.put( name, value );
}
/**
* Return a string representation of the object for debugging
*
* @return A string representation of the object
*/
public String toString() {
StringBuffer sb = new StringBuffer("LDAPConstraints {");
sb.append("time limit " + getTimeLimit() + ", ");
sb.append("referrals " + getReferralFollowing() + ", ");
sb.append("hop limit " + getHopLimit() + ", ");
sb.append("referral handler " + getReferralHandler() + ", ");
LDAPControl[] controls = getControls();
if ( controls != null ) {
sb.append(", server controls ");
for (int i =0; i < controls.length; i++) {
sb.append(controls[i].toString());
if ( i < (controls.length - 1) ) {
sb.append(" ");
}
}
}
sb.append('}');
return sb.toString();
}
/**
* Makes a copy of an existing set of constraints.
* @return a copy of an existing set of constraints
*/
public Object clone() {
LDAPConstraints o = new LDAPConstraints();
o._time_limit = this._time_limit;
o.referrals = this.referrals;
o._referralHandler = this._referralHandler;
o._hop_limit = this._hop_limit;
if ( (this._serverControls != null) &&
(this._serverControls.length > 0) ) {
o._serverControls = new LDAPControl[this._serverControls.length];
for( int i = 0; i < this._serverControls.length; i++ )
o._serverControls[i] =
(LDAPControl)this._serverControls[i].clone();
}
return o;
}
}

View File

@@ -0,0 +1,506 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
import org.ietf.ldap.ber.stream.*;
import org.ietf.ldap.client.*;
import org.ietf.ldap.util.*;
import org.ietf.ldap.controls.*;
/**
* Represents arbitrary control data that can be used with a
* a particular LDAP operation. LDAP controls are part of version 3
* of the LDAP protocol.
* <P>
*
* LDAP controls allow you to extend the functionality of
* an LDAP operation. For example, you can use an LDAP control
* for the search operation to sort search results on an LDAP server.
* <P>
*
* An LDAP control can be either a <B>server control</B> or
* a <B>client control</B>:
* <P>
* <UL>
* <LI><B>Server controls</B> can be sent to the LDAP server or returned
* by the server on any operation.
* <LI><B>Client controls</B> are intended to affect only the client side
* of the operation.
* </UL>
* <P>
*
* An LDAP control consists of the following information:
* <P>
* <UL>
* <LI>A unique object ID (OID) that identifies the control.<P>
* <LI>A &quot;criticality&quot; field, which indicates whether or
* not the control is critical to the operation. (If the control is
* critical to the operation and the server does not support the control,
* the server should not execute the operation.)<P>
* <LI>Data pertaining to the control.<P>
* </UL>
* <P>
*
* To determine which server controls are supported by a particular server,
* you need to search for the root DSE (DSA-specific entry, where DSA is
* another term for &quot;LDAP server&quot;) and find the values of the
* <CODE>supportedControl</CODE> attribute. This attribute contains the
* object IDs (OIDs) of the controls supported by this server.
* <P>
*
* The following section of code demonstrates how to get the list
* of the server controls supported by an LDAP server.
* <P>
*
* <PRE>
* public static void main( String[] args )
* {
* LDAPConnection ld = new LDAPConnection();
* try {
* String MY_HOST = "localhost";
* int MY_PORT = 389;
* ld.connect( MY_HOST, MY_PORT );
* try {
* ld.authenticate( 3, "cn=Directory Manager", "23skidoo" );
* } catch( LDAPException e ) {
* System.out.println( "LDAP server does not support v3." );
* ld.disconnect();
* System.exit(1);
* }
*
* String MY_FILT = "(objectclass=*)";
* String MY_BASE = "";
* String getAttrs[] = { "supportedControl" };
* LDAPSearchResults res = ld.search( MY_BASE,
* LDAPConnection.SCOPE_BASE, MY_FILT, getAttrs, false );
*
* while ( res.hasMoreElements() ) {
* LDAPEntry findEntry = (LDAPEntry)res.nextElement();
* LDAPAttributeSet findAttrs = findEntry.getAttributeSet();
* Enumeration enumAttrs = findAttrs.getAttributes();
*
* while ( enumAttrs.hasMoreElements() ) {
* LDAPAttribute anAttr = (LDAPAttribute)enumAttrs.nextElement();
* String attrName = anAttr.getName();
* System.out.println( attrName );
* Enumeration enumVals = anAttr.getStringValues();
*
* while ( enumVals.hasMoreElements() ) {
* String aVal = ( String )enumVals.nextElement();
* System.out.println( "\t" + aVal );
* }
* }
* }
* }
* catch( LDAPException e ) {
* System.out.println( "Error: " + e.toString() );
* }
* try {
* ld.disconnect();
* }
* catch( LDAPException e ) {
* System.exit(1);
* }
* System.exit(0);
* }
* </PRE>
* <P>
*
* If you compile and run this example against an LDAP server that
* supports v3 of the protocol, you might receive the following results:
* <P>
*
* <PRE>
* supportedcontrol
* 2.16.840.1.113730.3.4.2
* 2.16.840.1.113730.3.4.3
* 2.16.840.1.113730.3.4.4
* 2.16.840.1.113730.3.4.5
* 1.2.840.113556.1.4.473
* </PRE>
* <P>
*
* For more information on LDAP controls, see the Internet-Draft on
* the LDAP v3 protocol. (Note that this internet draft is still a
* work in progress. You can find the latest draft at the <A
* HREF="http://www.ietf.cnri.reston.va.us/html.charters/asid-charter.html"
* TARGET="_blank">ASID home page</A>.
* <P>
*
* @version 1.0
* @see org.ietf.ldap.LDAPConnection#search(java.lang.String, int, java.lang.String, java.lang.String[], boolean)
* @see org.ietf.ldap.LDAPConnection#getOption
* @see org.ietf.ldap.LDAPConnection#setOption
* @see org.ietf.ldap.LDAPConnection#getResponseControls
* @see org.ietf.ldap.LDAPConstraints#getControls
* @see org.ietf.ldap.LDAPConstraints#setControls
*/
public class LDAPControl implements Cloneable, Serializable {
static final long serialVersionUID = 5149887553272603753L;
public final static String MANAGEDSAIT = "2.16.840.1.113730.3.4.2";
/* Password information sent back to client */
public final static String PWEXPIRED = "2.16.840.1.113730.3.4.4";
public final static String PWEXPIRING = "2.16.840.1.113730.3.4.5";
/**
* Default constructor for the <CODE>LDAPControl</CODE> class.
*/
public LDAPControl()
{
}
/**
* Constructs a new <CODE>LDAPControl</CODE> object using the
* specified object ID (OID), &quot;criticality&quot; field, and
* data to be used by the control.
* <P>
*
* @param id the object ID (OID) identifying the control
* @param critical <CODE>true</CODE> if the LDAP operation should be
* cancelled when the server does not support this control (in other
* words, this control is critical to the LDAP operation)
* @param vals control-specific data
* @see org.ietf.ldap.LDAPConstraints#setControls
*/
public LDAPControl( String id,
boolean critical,
byte vals[] ) {
_oid = id;
_critical = critical;
_value = vals;
}
/**
* Gets the object ID (OID) of the control.
* @return object ID (OID) of the control.
*/
public String getID() {
return _oid;
}
/**
* Specifies whether or not the control is critical to the LDAP operation.
* @return <CODE>true</CODE> if the LDAP operation should be cancelled when
* the server does not support this control.
*/
public boolean isCritical() {
return _critical;
}
/**
* Gets the data in the control.
* @return the data in the control as a byte array.
*/
public byte[] getValue() {
return _value;
}
/**
* Gets the ber representation of control.
* @return ber representation of control.
*/
BERElement getBERElement() {
BERSequence seq = new BERSequence();
seq.addElement(new BEROctetString (_oid));
seq.addElement(new BERBoolean (_critical));
if ( (_value == null) || (_value.length < 1) )
seq.addElement(new BEROctetString ((byte[])null));
else {
seq.addElement(new BEROctetString (_value, 0, _value.length));
}
return seq;
}
/**
* Associates a class with an oid. This class must be an extension of
* <CODE>LDAPControl</CODE>, and should implement the <CODE>LDAPControl(
* String oid, boolean critical, byte[] value)</CODE> constructor to
* instantiate the control.
* @param oid the string representation of the oid
* @param controlClass the class that instantatiates the control associated
* with oid
* @exception org.ietf.ldap.LDAPException If the class parameter is not
* a subclass of <CODE>LDAPControl</CODE> or the class parameter does not
* implement the <CODE>LDAPControl(String oid, boolean critical, byte[] value)
* </CODE> constructor.
*/
public static void register( String oid, Class controlClass )
throws LDAPException {
if (controlClass == null) {
return;
}
// 1. make sure controlClass is a subclass of LDAPControl
Class superClass = controlClass;
while (superClass != LDAPControl.class && superClass != null) {
superClass = superClass.getSuperclass();
}
if (superClass == null)
throw new LDAPException("controlClass must be a subclass of " +
"LDAPControl", LDAPException.PARAM_ERROR);
// 2. make sure controlClass has the proper constructor
Class[] cparams = { String.class, boolean.class, byte[].class };
try {
controlClass.getConstructor(cparams);
} catch (NoSuchMethodException e) {
throw new LDAPException("controlClass does not implement the " +
"correct contstructor",
LDAPException.PARAM_ERROR);
}
// 3. check if the hash table exists
if (_controlClassHash == null) {
_controlClassHash = new Hashtable();
}
// 4. add the controlClass
_controlClassHash.put(oid, controlClass);
}
/**
* Returns the <CODE>Class</CODE> that has been registered to oid.
* @param oid a String that associates the control class to a control
* @return a <CODE>Class</CODE> that can instantiate a control of the
* type specified by oid.
* @see org.ietf.ldap.LDAPControl#register
*
*/
protected static Class lookupControlClass( String oid ) {
if ( _controlClassHash == null ) {
return null;
}
return (Class)_controlClassHash.get(oid);
}
/**
* Returns a <CODE>LDAPControl</CODE> object instantiated by the Class
* associated by <CODE>LDAPControl.register</CODE> to the oid. If
* no Class is found for the given control, or an exception occurs when
* attempting to instantiate the control, a basic <CODE>LDAPControl</CODE>
* is instantiated using the parameters.
* @param oid the oid of the control to instantiate
* @param critical <CODE>true</CODE> if this is a critical control
* @param value the byte value for the control
* @return a newly instantiated <CODE>LDAPControl</CODE>.
* @see org.ietf.ldap.LDAPControl#register
*/
protected static LDAPControl createControl( String oid,
boolean critical,
byte[] value ) {
Class controlClass = lookupControlClass(oid);
if ( controlClass == null ) {
return new LDAPControl(oid, critical, value);
}
Class[] cparams = { String.class, boolean.class, byte[].class };
Constructor creator = null;
try {
creator = controlClass.getConstructor(cparams);
} catch (NoSuchMethodException e) {
//shouldn't happen, but...
System.err.println("Caught java.lang.NoSuchMethodException while" +
" attempting to instantiate a control of type " +
oid);
return new LDAPControl(oid, critical, value);
}
Object[] oparams = { oid, new Boolean(critical), value } ;
LDAPControl returnControl = null;
try {
returnControl = (LDAPControl)creator.newInstance(oparams);
} catch (Exception e) {
String eString = null;
if (e instanceof InvocationTargetException) {
eString = ((InvocationTargetException)
e).getTargetException().toString();
} else {
eString = e.toString();
}
System.err.println("Caught " + eString + " while attempting to" +
" instantiate a control of type " +
oid);
returnControl = new LDAPControl(oid, critical, value);
}
return returnControl;
}
/**
* Returns a <CODE>LDAPControl</CODE> object instantiated by the Class
* associated by <CODE>LDAPControl.register</CODE> to the oid. If
* no Class is found for the given control, or an exception occurs when
* attempting to instantiate the control, a basic <CODE>LDAPControl</CODE>
* is instantiated using the parameters.
* @param el the <CODE>BERElement</CODE> containing the control
* @return a newly instantiated <CODE>LDAPControl</CODE>.
* @see org.ietf.ldap.LPAPControl#register
*
* Note:
* This code was extracted from <CODE>JDAPControl(BERElement el)</CODE>
* constructor.
*/
static LDAPControl parseControl( BERElement el ) {
BERSequence s = (BERSequence)el;
String oid = null;
boolean critical = false;
byte[] value = null;
try{
oid = new String(((BEROctetString)s.elementAt(0)).getValue(), "UTF8");
} catch(Throwable x) {}
Object obj = s.elementAt(1);
if (obj instanceof BERBoolean) {
critical = ((BERBoolean)obj).getValue();
}
else {
value = ((BEROctetString)obj).getValue();
}
if (s.size() >= 3) {
value = ((BEROctetString)s.elementAt(2)).getValue();
}
return createControl(oid, critical, value);
}
/**
* Instantiates all of the controls contained within the LDAP message
* fragment specified by data and returns them in an <CODE>LDAPControl</CODE>
* array. This fragment can be either the entire LDAP message or just the
* control section of the message.
* <P>
* If an exception occurs when instantiating a control, that control is
* returned as a basic <CODE>LDAPControl</CODE>.
* @param data the LDAP message fragment in raw BER format
* @return an <CODE>LDAPControl</CODE> array containing all of the controls
* from the message fragment.
* @exception java.lang.IOException If the data passed to this method
* is not a valid LDAP message fragment.
* @see org.ietf.ldap.LDAPControl#register
*/
public static LDAPControl[] newInstance(byte[] data) throws IOException {
int[] bread = { 0 };
BERElement el = BERElement.getElement(new JDAPBERTagDecoder(),
new ByteArrayInputStream(data),
bread);
LDAPControl[] jc = null;
try {
// see if data is a LDAP message
LDAPMessage msg = LDAPMessage.parseMessage(el);
return msg.getControls();
} catch (IOException e) {
// that didn't work; let's see if its just the controls
BERTag tag = (BERTag)el;
if ( tag.getTag() == (BERTag.CONSTRUCTED|BERTag.CONTEXT|0) ) {
BERSequence controls = (BERSequence)tag.getValue();
jc = new LDAPControl[controls.size()];
for (int i = 0; i < controls.size(); i++) {
jc[i] = parseControl(controls.elementAt(i));
}
}
}
return jc;
}
/**
* Creates a copy of the control
*
* @return copy of the control
*/
public Object clone() {
byte[] vals = null;
if ( _value != null ) {
vals = new byte[_value.length];
for( int i = 0; i < _value.length; i++ )
vals[i] = _value[i];
}
LDAPControl control = new LDAPControl( _oid, _critical, vals );
return control;
}
/**
* Create a "flattened" BER encoding from a BER,
* and return it as a byte array.
* @param ber a BER encoded sequence
* @return the byte array of encoded data.
*/
protected byte[] flattenBER( BERSequence ber ) {
/* Suck out the data and return it */
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
try {
ber.write( outStream );
} catch ( IOException e ) {
return null;
}
return outStream.toByteArray();
}
/**
* Return a string representation of the control for debugging
*
* @return a string representation of the control.
*/
public String toString() {
String s = getID() + ' ' + isCritical();
if ( _value != null ) {
s += ' ' + LDIF.toPrintableString( _value );
}
return "LDAPControl {" + s + '}';
}
private String _oid;
protected boolean _critical = false;
protected byte[] _value = null;
static private Hashtable _controlClassHash = null;
static {
try {
LDAPControl.register( LDAPPasswordExpiringControl.EXPIRING,
LDAPPasswordExpiringControl.class );
LDAPControl.register( LDAPPasswordExpiredControl.EXPIRED,
LDAPPasswordExpiredControl.class );
LDAPControl.register( LDAPEntryChangeControl.ENTRYCHANGED,
LDAPEntryChangeControl.class );
LDAPControl.register( LDAPSortControl.SORTRESPONSE,
LDAPSortControl.class );
LDAPControl.register( LDAPVirtualListResponse.VIRTUALLISTRESPONSE,
LDAPVirtualListResponse.class );
} catch (LDAPException e) {
}
}
}

View File

@@ -0,0 +1,363 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
/**
* The definition of a DIT content rule in the schema.
* <A HREF="http://www.ietf.org/rfc/rfc2252.txt"
* TARGET="_blank">RFC 2252, Lightweight Directory Access Protocol (v3):
* DIT Content Rule Description</A> covers the types of information
* to specify when defining a DIT content rule. According to the RFC,
* the description of a DIT content rule can include the following:
* <P>
*
* <UL>
* <LI>an OID identifying the attribute type
* <LI>a name identifying the attribute type
* <LI>a description of the attribute type
* <LI>the name of the parent attribute type
* <LI>the syntax used by the attribute (for example,
* <CODE>cis</CODE> or <CODE>int</CODE>)
* <LI>an indication of whether the attribute type is single-valued
* or multi-valued
* </UL>
* <P>
*
* When you construct an <CODE>LDAPDITContentRuleSchema</CODE> object, you can
* specify these types of information as arguments to the constructor or
* in the AttributeTypeDescription format specified in RFC 2252.
* When an LDAP client searches an LDAP server for the schema, the server
* returns schema information as an object with attribute values in this
* format.
* <P>
*
* There are a number of additional optional description fields which
* are not explicitly accessible through LDAPDITContentRuleSchema, but which
* can be managed with setQualifier, getQualifier, and getQualifierNames:
* <P>
*
* <UL>
* <LI>OBSOLETE
* </UL>
* <P>
*
* To get the name, OID, and description of this DIT content rule
* , use the <CODE>getName</CODE>, <CODE>getOID</CODE>, and
* <CODE>getDescription</CODE> methods inherited from the abstract class
* <CODE>LDAPSchemaElement</CODE>. Optional and custom qualifiers are
* accessed with <CODE>getQualifier</CODE> and <CODE>getQualifierNames</CODE>
* from <CODE>LDAPSchemaElement</CODE>.
* <P>
*
* To add or remove this attribute type definition from the
* schema, use the <CODE>add</CODE> and <CODE>remove</CODE>
* methods, which this class inherits from the <CODE>LDAPSchemaElement</CODE>
* abstract class.
* <P>
* RFC 2252 defines DITContentRuleDescription as follows:
* <P>
* <PRE>
* DITContentRuleDescription = "("
* numericoid ; Structural ObjectClass identifier
* [ "NAME" qdescrs ]
* [ "DESC" qdstring ]
* [ "OBSOLETE" ]
* [ "AUX" oids ] ; Auxiliary ObjectClasses
* [ "MUST" oids ] ; AttributeType identifiers
* [ "MAY" oids ] ; AttributeType identifiers
* [ "NOT" oids ] ; AttributeType identifiers
* ")"
* </PRE>
*
* @version 1.0
* @see org.ietf.ldap.LDAPSchemaElement
**/
public class LDAPDITContentRuleSchema extends LDAPSchemaElement {
static final long serialVersionUID = -8588488481097270056L;
/**
* Constructs a blank element.
*/
protected LDAPDITContentRuleSchema() {
super();
}
/**
* Constructs a DIT content rule definition, using the specified
* information.
* @param names names of the attribute type
* @param oid object identifier (OID) of the attribute type
* in dotted-string format (for example, "1.2.3.4")
* @param description description of attribute type
* @param obsolete <code>true</code> if the rule is obsolete
* @param auxiliary a list of auxiliary object classes
* allowed for an entry to which this content rule applies.
* These may either be specified by name or numeric oid.
* @param required a list of user attribute types that an entry
* to which this content rule applies must contain in addition to
* its normal set of mandatory attributes. These may either be
* specified by name or numeric oid.
* @param optional a list of user attribute types that an entry
* to which this content rule applies may contain in addition to
* its normal set of optional attributes. These may either be
* specified by name or numeric oid.
* @param precluded a list consisting of a subset of the optional
* user attribute types of the structural and auxiliary object
* classes which are precluded from an entry to which this content rule
* applies. These may either be specified by name or numeric oid.
*/
public LDAPDITContentRuleSchema( String[] names,
String oid,
String description,
boolean obsolete,
String[] auxiliary,
String[] required,
String[] optional,
String[] precluded ) {
super( names, oid, description );
if ( required != null ) {
for( int i = 0; i < required.length; i++ ) {
must.addElement( required[i] );
}
}
if ( optional != null ) {
for( int i = 0; i < optional.length; i++ ) {
may.addElement( optional[i] );
}
}
if ( auxiliary != null ) {
for( int i = 0; i < auxiliary.length; i++ ) {
aux.addElement( auxiliary[i] );
}
}
if ( precluded != null ) {
for( int i = 0; i < precluded.length; i++ ) {
not.addElement( precluded[i] );
}
}
if ( obsolete ) {
setQualifier( OBSOLETE, "" );
}
}
/**
* Constructs a DIT content rule definition based on a description in
* the DITContentRuleDescription format. For information on this format,
* (see <A HREF="http://www.ietf.org/rfc/rfc2252.txt"
* >RFC 2252, Lightweight Directory Access Protocol (v3):
* DIT Content Rule Description</A>. This is the format that LDAP servers
* and clients use to exchange schema information. (For example, when
* you search an LDAP server for its schema, the server returns an entry
* with the attributes "objectclasses" and "attributetypes". The
* values of "attributetypes" are attribute type descriptions
* in this format.)
* <P>
*
* @param raw definition of the DIT content rule in the
* DITContentRuleDescription format
*/
public LDAPDITContentRuleSchema( String raw ) {
attrName = "ditContentRules";
parseValue( raw );
Object o = properties.get( MAY );
if ( o != null ) {
if ( o instanceof Vector ) {
may = (Vector)o;
} else {
may.addElement( o );
}
}
o = properties.get( MUST );
if ( o != null ) {
if ( o instanceof Vector ) {
must = (Vector)o;
} else {
must.addElement( o );
}
}
o = properties.get( NOT );
if ( o != null ) {
if ( o instanceof Vector ) {
not = (Vector)o;
} else {
not.addElement( o );
}
}
o = properties.get( AUX );
if ( o != null ) {
if ( o instanceof Vector ) {
aux = (Vector)o;
} else {
aux.addElement( o );
}
}
}
/**
* Gets the names of the auxiliary object classes allowed
* in this content rule.
* @return the names of auxiliary object classes
* allowed in this content rule.
*/
public String[] getAuxiliaryClasses() {
String[] vals = new String[aux.size()];
aux.copyInto( vals );
return vals;
}
/**
* Gets the names of optional attributes allowed
* in this content rule.
* @return the names of optional attributes
* allowed in this content rule.
*/
public String[] getOptionalAttributes() {
String[] vals = new String[may.size()];
may.copyInto( vals );
return vals;
}
/**
* Gets the names of the precluded attributes for
* this content rule.
* @return the names of the precluded attributes
* for this content rule.
*/
public String[] getPrecludedAttributes() {
String[] vals = new String[not.size()];
not.copyInto( vals );
return vals;
}
/**
* Gets the names of the required attributes for
* this content rule.
* @return the names of the required attributes
* for this content rule.
*/
public String[] getRequiredAttributes() {
String[] vals = new String[must.size()];
must.copyInto( vals );
return vals;
}
/**
* Gets the attribute name for a schema element
*
* @return The attribute name of the element
*/
String getAttributeName() {
return "ldapditcontentrules";
}
/**
* Prepares a value in RFC 2252 format for submission to a server
*
* @return a String ready for submission to an LDAP server.
*/
String getValue() {
String s = getValuePrefix();
String val = getOptionalValues( NOVALS );
if ( val.length() > 0 ) {
s += val + ' ';
}
if ( aux.size() > 0 ) {
s += AUX + " " + vectorToList( aux );
s += ' ';
}
if ( must.size() > 0 ) {
s += MUST + " " + vectorToList( must );
s += ' ';
}
if ( may.size() > 0 ) {
s += MAY + " " + vectorToList( may );
s += ' ';
}
if ( not.size() > 0 ) {
s += NOT + " " + vectorToList( not );
s += ' ';
}
val = getCustomValues();
if ( val.length() > 0 ) {
s += val + ' ';
}
s += ')';
return s;
}
/**
* Creates a list within parentheses, with $ as delimiter
*
* @param vals values for list
* @return a String with a list of values.
*/
protected String vectorToList( Vector vals ) {
String val = "( ";
for( int i = 0; i < vals.size(); i++ ) {
val += (String)vals.elementAt(i) + ' ';
if ( i < (vals.size() - 1) ) {
val += "$ ";
}
}
val += ')';
return val;
}
/**
* Gets the definition of the rule in Directory format
*
* @return definition of the rule in Directory format
*/
public String toString() {
return getValue();
}
public final static String AUX = "AUX";
public final static String MUST = "MUST";
public final static String MAY = "MAY";
public final static String NOT = "NOT";
// Qualifiers known to not have values; prepare a Hashtable
static final String[] NOVALS = { "OBSOLETE" };
static {
for( int i = 0; i < NOVALS.length; i++ ) {
novalsTable.put( NOVALS[i], NOVALS[i] );
}
}
// Qualifiers which we output explicitly in toString()
static final String[] IGNOREVALS = { OBSOLETE,
AUX,
MUST,
MAY,
NOT
};
private Vector must = new Vector();
private Vector may = new Vector();
private Vector aux = new Vector();
private Vector not = new Vector();
}

View File

@@ -0,0 +1,269 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The structures of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
/**
* The definition of a DIT structure rule in the schema.
* <A HREF="http://www.ietf.org/rfc/rfc2252.txt"
* TARGET="_blank">RFC 2252, Lightweight Directory Access Protocol (v3):
* DIT Structure Rule Description</A> covers the types of information
* to specify when defining a DIT structure rule. According to the RFC,
* the description of a DIT structure rule can include the following:
* <P>
*
* <UL>
* <LI>an OID identifying the attribute type
* <LI>a name identifying the attribute type
* <LI>a description of the attribute type
* <LI>the name of the parent attribute type
* <LI>the syntax used by the attribute (for example,
* <CODE>cis</CODE> or <CODE>int</CODE>)
* <LI>an indication of whether the attribute type is single-valued
* or multi-valued
* </UL>
* <P>
*
* When you construct an <CODE>LDAPDITStructureRuleSchema</CODE> object, you can
* specify these types of information as arguments to the constructor or
* in the AttributeTypeDescription format specified in RFC 2252.
* When an LDAP client searches an LDAP server for the schema, the server
* returns schema information as an object with attribute values in this
* format.
* <P>
*
* There are a number of additional optional description fields which
* are not explicitly accessible through LDAPDITStructureRuleSchema, but which
* can be managed with setQualifier, getQualifier, and getQualifierNames:
* <P>
*
* <UL>
* <LI>OBSOLETE
* </UL>
* <P>
*
* To get the name, OID, and description of this DIT structure rule
* , use the <CODE>getName</CODE>, <CODE>getOID</CODE>, and
* <CODE>getDescription</CODE> methods inherited from the abstract class
* <CODE>LDAPSchemaElement</CODE>. Optional and custom qualifiers are
* accessed with <CODE>getQualifier</CODE> and <CODE>getQualifierNames</CODE>
* from <CODE>LDAPSchemaElement</CODE>.
* <P>
*
* To add or remove this attribute type definition from the
* schema, use the <CODE>add</CODE> and <CODE>remove</CODE>
* methods, which this class inherits from the <CODE>LDAPSchemaElement</CODE>
* abstract class.
* <P>
* RFC 2252 defines DITStructureRuleDescription as follows:
* <P>
* <PRE>
* DITStructureRuleDescription = "(" whsp
* ruleidentifier whsp ; DITStructureRule identifier
* [ "NAME" qdescrs ]
* [ "DESC" qdstring ]
* [ "OBSOLETE" whsp ]
* "FORM" woid whsp ; NameForm
* [ "SUP" ruleidentifiers whsp ] ; superior DITStructureRules
* ")"
* </PRE>
*
* @version 1.0
* @see org.ietf.ldap.LDAPSchemaElement
**/
public class LDAPDITStructureRuleSchema extends LDAPSchemaElement {
static final long serialVersionUID = -2823317246039655811L;
/**
* Constructs a blank element.
*/
protected LDAPDITStructureRuleSchema() {
super();
}
/**
* Constructs a DIT structure rule definition, using the specified
* information.
* @param names names of the element
* @param ruleID unique identifier of the structure rule.<BR>
* NOTE: this is an integer, not a dotted numerical identifier.
* Structure rules aren't identified by OID.
* @param description description of attribute type
* @param obsolete <code>true</code> if the rule is obsolete
* @param nameForm either the identifier or name of a name form.
* This is used to indirectly refer to the object class that this
* structure rule applies to.
* @param superiors list of superior structure rules - specified
* by their integer ID. The object class specified by this structure
* rule (via the nameForm parameter) may only be subordinate in
* the DIT to object classes of those represented by the structure
* rules here.
*/
public LDAPDITStructureRuleSchema( String[] names,
int ruleID,
String description,
boolean obsolete,
String nameForm,
String[] superiors ) {
super( names, "", description );
this.nameForm = nameForm;
this.ruleID = ruleID;
if ( obsolete ) {
setQualifier( OBSOLETE, "" );
}
if ( (superiors != null) && (superiors.length > 0) ) {
setQualifier( SUPERIOR, superiors );
}
}
/**
* Constructs a DIT structure rule definition based on a description in
* the DITStructureRuleDescription format. For information on this format,
* (see <A HREF="http://www.ietf.org/rfc/rfc2252.txt"
* >RFC 2252, Lightweight Directory Access Protocol (v3):
* DIT Structure Rule Description</A>. This is the format that
* LDAP servers
* and clients use to exchange schema information. (For example, when
* you search an LDAP server for its schema, the server returns an entry
* with the attributes "objectclasses" and "attributetypes". The
* values of "attributetypes" are attribute type descriptions
* in this format.)
* <P>
*
* @param raw definition of the DIT structure rule in the
* DITStructureRuleDescription format
*/
public LDAPDITStructureRuleSchema( String raw ) {
attrName = "ditStructureRules";
parseValue( raw );
Object o = properties.get( FORM );
if ( o != null ) {
nameForm = (String)o;
}
try {
ruleID = Integer.parseInt( oid );
} catch ( Exception e ) {
}
}
/**
* Returns the NameForm that this structure rule controls. You can get
* the actual object class that this structure rule controls by calling
* getNameForm().getObjectClass().
*
* @return the NameForm that this structure rule controls.
*/
public String getNameForm() {
return nameForm;
}
/**
* Returns the rule ID for this structure rule. Note that this returns
* an integer rather than a dotted decimal OID. Objects of this class do
* not have an OID, thus getID will return null.
*
* @return the rule ID for this structure rule.
*/
public int getRuleID() {
return ruleID;
}
/**
* Returns a list of all structure rules that are superior to this
* structure rule. To resolve to an object class, you need to first
* resolve the superior id to another structure rule, then call
* getNameForm().getObjectClass() on that structure rule.
* @return the structure rules that are superior to this
* structure rule.
*/
public String[] getSuperiors() {
return getQualifier( SUPERIOR );
}
/**
* Prepares a value in RFC 2252 format for submission to a server
*
* @return a String ready for submission to an LDAP server.
*/
String getValue() {
String s = "( " + ruleID + ' ';
s += getNameField();
if ( description != null ) {
s += "DESC \'" + description + "\' ";
}
if ( isObsolete() ) {
s += OBSOLETE + ' ';
}
s += FORM + " " + nameForm + ' ';
String val = getValue( SUPERIOR, false );
if ( (val != null) && (val.length() > 1) ) {
s += val + ' ';
}
val = getCustomValues();
if ( val.length() > 0 ) {
s += val + ' ';
}
s += ')';
return s;
}
/**
* Gets the definition of the rule in Directory format
*
* @return definition of the rule in Directory format
*/
public String toString() {
return getValue();
}
/**
* Gets the attribute name for a schema element
*
* @return The attribute name of the element
*/
String getAttributeName() {
return "ldapditstructurerules";
}
public final static String FORM = "FORM";
// Qualifiers known to not have values; prepare a Hashtable
static final String[] NOVALS = { "OBSOLETE" };
static {
for( int i = 0; i < NOVALS.length; i++ ) {
novalsTable.put( NOVALS[i], NOVALS[i] );
}
}
// Qualifiers which we output explicitly in toString()
static final String[] IGNOREVALS = { OBSOLETE,
FORM,
"SUP"
};
private String nameForm = null;
private int ruleID = 0;
}

View File

@@ -0,0 +1,185 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
import org.ietf.ldap.util.*;
import java.io.*;
/**
* Represents a distinguished name in LDAP.
* <P>
*
* You can use objects of this class to split a distinguished name
* (DN) into its individual components. You can also escape the
* characters in a DN.
* <P>
*
* @version 1.0
*/
public class LDAPDN {
/**
* Returns the individual components of a relative distinguished name (RDN).
* @param rdn relative distinguished name of which you want to get the components.
* @param noTypes if <CODE>true</CODE>, returns only the values of the
* components and not the names (such as 'cn=')
* @return an array of strings representing the components of the RDN.
* @see org.ietf.ldap.LDAPDN#explodeDN(java.lang.String, boolean)
*/
public static String[] explodeRDN (String rdn, boolean noTypes) {
RDN name = new RDN(rdn);
if ( noTypes ) {
return name.getValues();
} else {
String[] str = new String[1];
str[0] = name.toString();
return str;
}
}
/**
* Compares two dn's for equality.
* @param dn1 the first dn to compare
* @param dn2 the second dn to compare
* @return true if the two dn's are equal
*/
public static boolean equals(String dn1, String dn2) {
return normalize(dn1).equals(normalize(dn2));
}
/**
* Returns the RDN after escaping the characters specified
* by <CODE>org.ietf.ldap.util.DN.ESCAPED_CHAR</CODE>.
* <P>
*
* @param rdn the RDN to escape
* @return the RDN with the characters escaped.
* @see org.ietf.ldap.util.DN#ESCAPED_CHAR
* @see org.ietf.ldap.LDAPDN#unEscapeRDN(java.lang.String)
*/
public static String escapeRDN(String rdn) {
RDN name = new RDN(rdn);
String[] val = name.getValues();
if (val == null)
return rdn;
StringBuffer[] buffer = new StringBuffer[val.length];
StringBuffer retbuf = new StringBuffer();
String[] types = name.getTypes();
for (int j = 0; j < val.length; j++ ) {
buffer[j] = new StringBuffer(val[j]);
int i=0;
while (i<buffer[j].length()) {
if (isEscape(buffer[j].charAt(i))) {
buffer[j].insert(i, '\\');
i++;
}
i++;
}
retbuf.append( ((retbuf.length() > 0) ? " + " : "") + types[j] + "=" +
( new String( buffer[j] ) ) );
}
return new String( retbuf );
}
/**
* Returns the individual components of a distinguished name (DN).
* @param dn distinguished name of which you want to get the components.
* @param noTypes if <CODE>true</CODE>, returns only the values of the
* components and not the names (such as 'cn=')
* @return an array of strings representing the components of the DN.
* @see org.ietf.ldap.LDAPDN#explodeRDN(java.lang.String, boolean)
*/
public static String[] explodeDN (String dn, boolean noTypes) {
DN name = new DN(dn);
return name.explodeDN(noTypes);
}
/**
* Returns true if the string conforms to distinguished name syntax;
* NOT IMPLEMENTED YET
*
* @param dn string to evaluate for distinguished name syntax
* @return true if the string conforms to distinguished name syntax
*/
public boolean isValid( String dn ) {
return true;
}
/**
* Normalizes the dn.
* @param dn the DN to normalize
* @return the normalized DN
*/
public static String normalize(String dn) {
return (new DN(dn)).toString();
}
/**
* Returns the RDN after unescaping any escaped characters.
* For a list of characters that are typically escaped in a
* DN, see <CODE>org.ietf.ldap.LDAPDN.ESCAPED_CHAR</CODE>.
* <P>
*
* @param rdn the RDN to unescape
* @return the unescaped RDN.
* @see org.ietf.ldap.util.DN#ESCAPED_CHAR
* @see org.ietf.ldap.LDAPDN#escapeRDN(java.lang.String)
*/
public static String unEscapeRDN(String rdn) {
RDN name = new RDN(rdn);
String[] vals = name.getValues();
if ( (vals == null) || (vals.length < 1) )
return rdn;
StringBuffer buffer = new StringBuffer(vals[0]);
StringBuffer copy = new StringBuffer();
int i=0;
while (i<buffer.length()) {
char c = buffer.charAt(i++);
if (c != '\\') {
copy.append(c);
}
else { // copy the escaped char following the back slash
if (i<buffer.length()) {
copy.append(buffer.charAt(i++));
}
}
}
return name.getTypes()[0]+"="+(new String(copy));
}
private static boolean isEscape(char c) {
for (int i=0; i<DN.ESCAPED_CHAR.length; i++)
if (c == DN.ESCAPED_CHAR[i])
return true;
return false;
}
}

View File

@@ -0,0 +1,207 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.io.Serializable;
import java.util.*;
/**
* Represents an entry in the directory.
*
* @version 1.0
*/
public class LDAPEntry implements Serializable {
static final long serialVersionUID = -5563306228920012807L;
private String dn = null;
private LDAPAttributeSet attrSet = null;
/**
* Constructs an empty entry.
*/
public LDAPEntry() {
dn = null;
attrSet = new LDAPAttributeSet();
}
/**
* Constructs a new entry with the specified distinguished name and with
* an empty attribute set.
* @param distinguishedName the distinguished name of the new entry
*/
public LDAPEntry( String distinguishedName ) {
dn = distinguishedName;
attrSet = new LDAPAttributeSet();
}
/**
* Constructs a new entry with the specified distinguished name and
* set of attributes.
* @param distinguishedName the distinguished name of the new entry
* @param attrs the set of attributes to assign to the new entry
* @see org.ietf.ldap.LDAPAttributeSet
*/
public LDAPEntry( String distinguishedName, LDAPAttributeSet attrs ) {
dn = distinguishedName;
attrSet = attrs;
}
/**
* Returns the distinguished name of the current entry.
* @return distinguished name of the current entry.
*/
public String getDN() {
return dn;
}
void setDN(String name) {
dn = name;
}
/**
* In an entry, returns the single attribute that exactly matches the
* specified attribute name.
* @param attrName name of attribute to return
* For example:
*<PRE>
* "cn" // Only a non-subtyped version of cn
* "cn;lang-ja" // Only a Japanese version of cn, will not
* // return "cn;lang-ja-JP-kanji", for example
*</PRE>
* @return attribute in the current entry that has exactly the same name,
* or null (if no attribute in the entry matches the specified name).
* @see org.ietf.ldap.LDAPAttribute
*/
public LDAPAttribute getAttribute(String attrName) {
return attrSet.getAttribute(attrName);
}
/**
* Returns the subtype that matches "attrName" and that best matches
* a language specification "lang". If there are subtypes other than
* "lang" subtypes included in attrName, e.g. "cn;binary", only
* attributes with all of those subtypes are returned. If lang is
* null or empty, the method behaves as getAttribute(attrName). If
* there are no matching attributes, null is returned.
*
* Example:<PRE>
* Assume the entry contains only the following attributes:
* <CODE>cn;lang-en</CODE>
* <CODE>cn;lang-ja-JP-kanji</CODE>
* <CODE>sn</CODE>
* getAttribute( "cn" ) returns <CODE>null</CODE>.
* getAttribute( "sn" ) returns the "<CODE>sn</CODE>" attribute.
* getAttribute( "cn", "lang-en-us" ) returns the "<CODE>cn;lang-en</CODE>" attribute.
* getAttribute( "cn", "lang-en" ) returns the "<CODE>cn;lang-en</CODE>" attribute.
* getAttribute( "cn", "lang-ja" ) returns <CODE>null</CODE>.
* getAttribute( "sn", "lang-en" ) returns the "<CODE>sn</CODE>" attribute.
*</PRE>
* <P>
* @param attrName name of attribute to find in the entry
* @param lang a language specification (for example, <CODE>lang-en</CODE>)
* @return the attribute that matches the base name and that best
* matches any specified language subtype.
* @see org.ietf.ldap.LDAPAttribute
*/
public LDAPAttribute getAttribute( String attrName, String lang ) {
return attrSet.getAttribute( attrName, lang );
}
/**
* Returns the attribute set of the entry.
* @return set of attributes in the entry.
* @see org.ietf.ldap.LDAPAttributeSet
*/
public LDAPAttributeSet getAttributeSet() {
return attrSet;
}
/**
* Creates a new attribute set containing only the attributes
* that have the specified subtypes.
* <P>
*
* For example, suppose an entry contains the following attributes:
* <P>
*
* <PRE>
* cn
* cn;lang-ja
* sn;phonetic;lang-ja
* sn;lang-us
* </PRE>
*
* If you call the <CODE>getAttributeSet</CODE> method and pass
* <CODE>lang-ja</CODE> as the argument, the method returns
* an attribute set containing the following attributes:
* <P>
*
* <PRE>
* cn;lang-ja
* sn;phonetic;lang-ja
* </PRE>
*
* @param subtype semi-colon delimited list of subtypes
* that you want to find in attribute names.
*<PRE>
* "lang-ja" // Only Japanese language subtypes
* "binary" // Only binary subtypes
* "binary;lang-ja" // Only Japanese language subtypes
* which also are binary
*</PRE>
* @return attribute set containing the attributes that have
* the specified subtypes.
* @see org.ietf.ldap.LDAPAttributeSet
* @see org.ietf.ldap.LDAPAttributeSet#getSubset
*/
public LDAPAttributeSet getAttributeSet(String subtype) {
return attrSet.getSubset(subtype);
}
/**
* Retrieves the string representation of the entry's
* distinguished name (DN) and its attributes.
* For example:
*
* <PRE>
* LDAPEntry: uid=bjensen, ou=People, o=airius.com; LDAPAttributeSet:
* LDAPAttribute {type='cn', values='Barbara Jensen,Babs Jensen'}
* LDAPAttribute {type='sn', values='Jensen'}LDAPAttribute {type='givenname',
* values='Barbara'}LDAPAttribute {type='objectclass', values='top,person,
* organizationalPerson,inetOrgPerson'}LDAPAttribute {type='ou',
* values='Product Development,People'}
* </PRE>
*
* @return string representation of the entry's DN and its attributes.
*/
public String toString() {
StringBuffer sb = new StringBuffer("LDAPEntry: ");
if ( dn != null ) {
sb.append(dn);
sb.append("; ");
}
if ( attrSet != null ) {
sb.append(attrSet.toString());
}
return sb.toString();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,171 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.io.Serializable;
/**
* Version 3 of the LDAP protocol include the means to define additional
* operations (&quot;extended operations&quot;) beyond the standard LDAP
* operations. An LDAP v3 client can send an extended operation request,
* identifying the operation by its unique object ID (OID). The server
* receives the request and if OID corresponds to an operation supported
* by the server, the server procoess the request and sends an extended
* operation response back to the client.
* <P>
*
* Objects of this class can be used to represent extended operation
* requests (sent by your client) or extended operation responses
* (returned by an LDAP v3 server).
* <P>
*
* To determine which extended operations are supported by a server,
* you need to search for the root DSE (DSA-specific entry, where DSA is
* another term for &quot;LDAP server&quot;) and find the values of the
* <CODE>supportedExtension</CODE> attribute. This attribute contains the
* object IDs (OIDs) of the extended operations supported by this server.
* <P>
*
* The following section of code demonstrates how to get the list
* of the extended operations supported by an LDAP server.
* <P>
*
* <PRE>
* public static void main( String[] args )
* {
* LDAPConnection ld = new LDAPConnection();
* try {
* String MY_HOST = "localhost";
* int MY_PORT = 389;
* ld.connect( MY_HOST, MY_PORT );
* try {
* ld.authenticate( 3, "cn=Directory Manager", "23skidoo" );
* } catch( LDAPException e ) {
* System.out.println( "LDAP server does not support v3." );
* ld.disconnect();
* System.exit(1);
* }
*
* String MY_FILT = "(objectclass=*)";
* String MY_BASE = "";
* String getAttrs[] = { "supportedExtension" };
* LDAPSearchResults res = ld.search( MY_BASE,
* LDAPConnection.SCOPE_BASE, MY_FILT, getAttrs, false );
*
* while ( res.hasMoreElements() ) {
* LDAPEntry findEntry = (LDAPEntry)res.nextElement();
* LDAPAttributeSet findAttrs = findEntry.getAttributeSet();
* Enumeration enumAttrs = findAttrs.getAttributes();
*
* while ( enumAttrs.hasMoreElements() ) {
* LDAPAttribute anAttr = (LDAPAttribute)enumAttrs.nextElement();
* String attrName = anAttr.getName();
* System.out.println( attrName );
* Enumeration enumVals = anAttr.getStringValues();
*
* while ( enumVals.hasMoreElements() ) {
* String aVal = ( String )enumVals.nextElement();
* System.out.println( "\t" + aVal );
* }
* }
* }
* }
* catch( LDAPException e ) {
* System.out.println( "Error: " + e.toString() );
* }
* try {
* ld.disconnect();
* }
* catch( LDAPException e ) {
* System.exit(1);
* }
* System.exit(0);
* }
* </PRE>
* <P>
*
* If you compile and run this example against an LDAP server that
* supports v3 of the protocol, you might receive the following results:
* <P>
*
* <PRE>
* supportedextension
* 1.2.3.4
* </PRE>
* <P>
*
* For more information on LDAP controls, see the Internet-Draft on
* the LDAP v3 protocol. (Note that this internet draft is still a
* work in progress. You can find the latest draft at the <A
* HREF="http://www.ietf.cnri.reston.va.us/html.charters/asid-charter.html"
* TARGET="_blank">ASID home page</A>.
* <P>
*
* @version 1.0
* @see org.ietf.ldap.LDAPConnection#extendedOperation(org.ietf.ldap.LDAPExtendedOperation)
* @see org.ietf.ldap.LDAPConnection#search(java.lang.String, int, java.lang.String, java.lang.String[], boolean)
*
*/
public class LDAPExtendedOperation implements Serializable {
static final long serialVersionUID = 4010382829133611945L;
/**
* Construct an object
* @param oid identifier for the particular operation
* @param vals operation-specific data
*/
public LDAPExtendedOperation( String oid, byte[] vals ) {
_oid = oid;
_vals = vals;
}
/**
* Gets the identifier for this operation
*
* @return identifier for the operation
*/
public String getID() {
return _oid;
}
/**
* Gets the data for this operation
*
* @return operation-specific data
*/
public byte[] getValue() {
return _vals;
}
/**
* Sets the data for this operation
*
* @param vals operation-specific data
*/
public void setValue( byte[] vals ) {
_vals = vals;
}
private String _oid;
private byte[] _vals;
}

View File

@@ -0,0 +1,70 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.io.Serializable;
import org.ietf.ldap.client.opers.JDAPExtendedResponse;
/**
* Represents a server response to an extended operation request.
*
* @version 1.0
*/
public class LDAPExtendedResponse extends LDAPResponse
implements Serializable {
static final long serialVersionUID = -3813049515964705320L;
/**
* Constructor
*
* @param msgid message identifier
* @param rsp extended operation response
* @paarm controls array of controls or null
*/
LDAPExtendedResponse( int msgid,
JDAPExtendedResponse rsp,
LDAPControl controls[] ) {
super(msgid, rsp, controls);
}
/**
* Returns the OID of the response
*
* @return the response OID
*/
public String getID() {
JDAPExtendedResponse result = (JDAPExtendedResponse)getProtocolOp();
return result.getID();
}
/**
* Returns the raw bytes of the value part of the response
*
* @return response as a raw array of bytes
*/
public byte[] getValue() {
JDAPExtendedResponse result = (JDAPExtendedResponse)getProtocolOp();
return result.getValue();
}
}

View File

@@ -0,0 +1,59 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
/**
* An exception thrown when the LDAP operation being invoked has
* been interrupted. For example, an application might interrupt a thread that
* is performing a search.
*
* @version 1.0
*/
public class LDAPInterruptedException extends LDAPException {
static final long serialVersionUID = 5267455101797397456L;
/**
* Constructs a default exception with a specified string of
* additional information. This string appears if you call
* the <CODE>toString()</CODE> method.
* <P>
*
* @param message the additional information
* @see org.ietf.ldap.LDAPInterruptedException#toString()
*/
LDAPInterruptedException( String message ) {
super( message, LDAPException.OTHER, (Throwable)null);
}
/**
* Gets the string representation of the exception.
*/
public String toString() {
String str = "org.ietf.ldap.LDAPInterruptedException: ";
String msg = super.getMessage();
if (msg != null) {
str +=msg;
}
return str;
}
}

View File

@@ -0,0 +1,302 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
/**
* The definition of a matching rule in the schema.
* <A HREF="http://ds.internic.net/rfc/rfc2252.txt"
* TARGET="_blank">RFC 2252, Lightweight Directory Access Protocol (v3):
* Attribute Syntax Definitions</A> covers the types of information
* that need to be specified in the definition of a matching rule.
* According to the RFC, the description of a matching rule can
* include the following information:
* <P>
*
* <UL>
* <LI>an OID identifying the matching rule
* <LI>a name identifying the matching rule
* <LI>a description of the matching rule
* <LI>the syntax of the matching rule
* </UL>
* <P>
*
* The <CODE>LDAPMatchingRuleSchema</CODE> class also specifies
* the matching rule "use description", which describes the
* attributes which can be used with the matching rule.
* <P>
*
* When you construct an <CODE>LDAPMatchingRuleSchema</CODE> object, you can
* specify these types of information as arguments to the constructor or
* in the MatchingRuleDescription and MatchingRuleUseDescription formats
* specified in RFC 2252.
* When an LDAP client searches an LDAP server for the schema, the server
* returns schema information as an object with attribute values in this
* format.
* <P>
*
* You can get the name, OID, and description of this matching rule
* definition by using the <CODE>getName</CODE>, <CODE>getOID</CODE>, and
* <CODE>getDescription</CODE> methods inherited from the abstract class
* <CODE>LDAPSchemaElement</CODE>. Custom qualifiers are
* accessed with <CODE>getQualifier</CODE> and <CODE>getQualifierNames</CODE>
* from <CODE>LDAPSchemaElement</CODE>.
* <P>
*
* To add or remove this matching rule definition from the
* schema, use the <CODE>add</CODE> and <CODE>remove</CODE>
* methods, which this class inherits from the <CODE>LDAPSchemaElement</CODE>
* abstract class.
* <P>
* RFC 2252 defines MatchingRuleDescription and MatchingRuleUseDescription
* as follows:
* <P>
* <PRE>
* MatchingRuleDescription = "(" whsp
* numericoid whsp ; MatchingRule identifier
* [ "NAME" qdescrs ]
* [ "DESC" qdstring ]
* [ "OBSOLETE" whsp ]
* "SYNTAX" numericoid
* whsp ")"
*
* Values of the matchingRuleUse list the attributes which are suitable
* for use with an extensible matching rule.
*
* MatchingRuleUseDescription = "(" whsp
* numericoid whsp ; MatchingRule identifier
* [ "NAME" qdescrs ]
* [ "DESC" qdstring ]
* [ "OBSOLETE" ]
* "APPLIES" oids ; AttributeType identifiers
* whsp ")"
* </PRE>
* <P>
* <CODE>LDAPMatchingRuleSchema</CODE> abstracts away from the two types and
* manages their relationships transparently.
*
* @version 1.0
* @see org.ietf.ldap.LDAPSchemaElement
**/
public class LDAPMatchingRuleSchema extends LDAPAttributeSchema {
static final long serialVersionUID = 6466155218986944131L;
/**
* Constructs a matching rule definition, using the specified
* information.
* @param names name of the matching rule
* @param oid object identifier (OID) of the matching rule
* in dotted-decimal format (for example, "1.2.3.4").
* @param description description of the matching rule.
* @param attributes array of the OIDs of the attributes for which
* the matching rule is applicable.
* @param obsolete <CODE>true</CODE> if the element is obsolete
* @param syntaxString syntax of this matching rule in dotted-decimal
* format
*/
public LDAPMatchingRuleSchema( String[] names,
String oid,
String description,
String[] attributes,
boolean obsolete,
String syntaxString ) {
if ( (oid == null) || (oid.trim().length() < 1) ) {
throw new IllegalArgumentException( "OID required" );
}
this.names = names;
this.oid = oid;
this.description = description;
attrName = "matchingrules";
syntaxElement.syntax = syntaxElement.syntaxCheck( syntaxString );
syntaxElement.syntaxString = syntaxString;
setQualifier( SYNTAX, syntaxElement.syntaxString );
_attributes = new String[attributes.length];
for( int i = 0; i < attributes.length; i++ ) {
this._attributes[i] = attributes[i];
}
if ( obsolete ) {
setQualifier( OBSOLETE, "" );
}
}
/**
* Constructs a matching rule definition based on descriptions in
* the MatchingRuleDescription format and MatchingRuleUseDescription
* format. For information on this format,
* (see <A HREF="http://ds.internic.net/rfc/rfc2252.txt"
* TARGET="_blank">RFC 2252, Lightweight Directory Access Protocol (v3):
* Attribute Syntax Definitions</A>. This is the format that LDAP servers
* and clients use to exchange schema information. For example, when
* you search an LDAP server for its schema, the server returns an entry
* with attributes that include "matchingrule" and "matchingruleuse".
* The values of these attributes are matching rule descriptions
* in this format.
* <P>
*
* @param raw definition of the matching rule in the
* MatchingRuleDescription format
* @param use definition of the use of the matching rule in the
* MatchingRuleUseDescription format
*/
public LDAPMatchingRuleSchema( String raw, String use ) {
attrName = "matchingrules";
if ( raw != null ) {
parseValue( raw );
}
if ( use != null ) {
parseValue( use );
}
Vector v = (Vector)properties.get( "APPLIES" );
if ( v != null ) {
_attributes = new String[v.size()];
v.copyInto( _attributes );
v.removeAllElements();
}
String val = (String)properties.get( "SYNTAX" );
if ( val != null ) {
syntaxElement.syntaxString = val;
syntaxElement.syntax = syntaxElement.syntaxCheck( val );
}
}
/**
* Gets the list of the OIDs of the attribute types which can be used
* with the matching rule.
* @return array of the OIDs of the attribute types which can be used
* with the matching rule.
*/
public String[] getAttributes() {
return _attributes;
}
/**
* Prepare a value in RFC 2252 format for submitting to a server
*
* @param quotingBug <CODE>true</CODE> if SUP and SYNTAX values are to
* be quoted; that is to satisfy bugs in certain LDAP servers.
* @return a String ready to be submitted to an LDAP server
*/
String getValue( boolean quotingBug ) {
String s = getValuePrefix();
if ( syntaxElement.syntaxString != null ) {
s += "SYNTAX ";
if ( quotingBug ) {
s += '\'';
}
s += syntaxElement.syntaxString;
if ( quotingBug ) {
s += '\'';
}
s += ' ';
}
String val = getCustomValues();
if ( val.length() > 0 ) {
s += val + ' ';
}
s += ')';
return s;
}
/**
* Gets the attribute name for a schema element
*
* @return The attribute name of the element
*/
String getAttributeName() {
return "matchingrules";
}
/**
* Gets the matching rule definition in the string representation
* of the MatchingRuleDescription data type defined in X.501 (see
* <A HREF="http://ds.internic.net/rfc/rfc2252.txt"
* TARGET="_blank">RFC 2252, Lightweight Directory Access Protocol
* (v3): Attribute Syntax Definitions</A>
* for a description of these formats).
* This is the format that LDAP servers and clients use to exchange
* schema information. (For example, when
* you search an LDAP server for its schema, the server returns an entry
* with the attributes "matchingrules" and "matchingruleuse". The
* values of these attributes are matching rule description and
* matching rule use description in these formats.)
* <P>
*
* @return a string in a format that can be used as the value of
* the <CODE>matchingrule</CODE> attribute (which describes
* a matching rule in the schema) of a <CODE>subschema</CODE> object
*/
String getValue() {
return getValue( false );
}
/**
* Gets the matching rule use definition in the string representation
* of the MatchingRuleUseDescription data type defined in X.501 (see
* <A HREF="http://ds.internic.net/rfc/rfc2252.txt"
* TARGET="_blank">RFC 2252, Lightweight Directory Access Protocol
* (v3): Attribute Syntax Definitions</A>
* for a description of these formats).
* This is the format that LDAP servers and clients use to exchange
* schema information. (For example, when
* you search an LDAP server for its schema, the server returns an entry
* with the attributes "matchingrules" and "matchingruleuse". The
* values of these attributes are matching rule description and
* matching rule use description in these formats.)
* <P>
*
* @return a string in a format that can be used as the value of
* the <CODE>matchingruleuse</CODE> attribute (which describes the use of
* a matching rule in the schema) of a <CODE>subschema</CODE> object
*/
public String getUseValue() {
String s = getValuePrefix();
if ( (_attributes != null) && (_attributes.length > 0) ) {
s += "APPLIES ( ";
for( int i = 0; i < _attributes.length; i++ ) {
if ( i > 0 )
s += " $ ";
s += _attributes[i];
}
s += " ) ";
}
s += ')';
return s;
}
/**
* Gets the definition of the matching rule in Directory format
*
* @return definition of the matching rule in Directory format
*/
public String toString() {
return getValue( false );
}
// Qualifiers tracked explicitly
static final String[] EXPLICIT = { OBSOLETE,
SYNTAX };
private String[] _attributes = null;
}

View File

@@ -0,0 +1,215 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
/**
* The definition of a matching rule use in the schema.
* <A HREF="http://ds.internic.net/rfc/rfc2252.txt"
* TARGET="_blank">RFC 2252, Lightweight Directory Access Protocol (v3):
* Attribute Syntax Definitions</A> covers the types of information
* that need to be specified in the definition of a matching rule use.
* According to the RFC, the description of a matching rule use can
* include the following information:
* <P>
*
* <UL>
* <LI>an OID identifying the matching rule
* <LI>a name identifying the matching rule use
* <LI>a description of the matching rule use
* <LI>a list of attributes the matching rule applies to
* </UL>
* <P>
*
* When you construct an <CODE>LDAPMatchingRuleUseSchema</CODE> object, you can
* specify these types of information as arguments to the constructor or
* in the MatchingRuleUseDescription format specified in RFC 2252.
* When an LDAP client searches an LDAP server for the schema, the server
* returns schema information as an object with values in this
* format.
* <P>
*
* You can get the name, OID, and description of this matching rule use
* definition by using the <CODE>getName</CODE>, <CODE>getOID</CODE>, and
* <CODE>getDescription</CODE> methods inherited from the abstract class
* <CODE>LDAPSchemaElement</CODE>. Custom qualifiers are
* accessed with <CODE>getQualifier</CODE> and <CODE>getQualifierNames</CODE>
* from <CODE>LDAPSchemaElement</CODE>.
* <P>
*
* To add or remove this matching rule definition from the
* schema, use the <CODE>add</CODE> and <CODE>remove</CODE>
* methods, which this class inherits from the <CODE>LDAPSchemaElement</CODE>
* abstract class.
* <P>
* RFC 2252 defines MatchingRuleUseDescription follows:
* <P>
* <PRE>
* Values of the matchingRuleUse list the attributes which are suitable
* for use with an extensible matching rule.
*
* MatchingRuleUseDescription = "(" whsp
* numericoid whsp ; MatchingRule identifier
* [ "NAME" qdescrs ]
* [ "DESC" qdstring ]
* [ "OBSOLETE" ]
* "APPLIES" oids ; AttributeType identifiers
* whsp ")"
* </PRE>
* <P>
*
* @version 1.0
* @see org.ietf.ldap.LDAPSchemaElement
* @see org.ietf.ldap.LDAPMatchingRuleSchema
**/
public class LDAPMatchingRuleUseSchema extends LDAPAttributeSchema {
/**
* Constructs a matching rule use definition, using the specified
* information.
* @param names names of the matching rule
* @param oid object identifier (OID) of the matching rule
* in dotted-decimal format (for example, "1.2.3.4")
* @param description description of the matching rule
* @param obsolete <CODE>true</CODE> if the element is obsolete
* @param attributes array of the OIDs of the attributes for which
* the matching rule is applicable
*/
public LDAPMatchingRuleUseSchema( String[] names,
String oid,
String description,
boolean obsolete,
String[] attributes ) {
if ( (oid == null) || (oid.trim().length() < 1) ) {
throw new IllegalArgumentException( "OID required" );
}
this.names = names;
this.oid = oid;
this.description = description;
attrName = "matchingruleuse";
_attributes = new String[attributes.length];
for( int i = 0; i < attributes.length; i++ ) {
_attributes[i] = attributes[i];
}
if ( obsolete ) {
setQualifier( OBSOLETE, "" );
}
}
/**
* Constructs a matching rule use definition based on descriptions in
* the MatchingRuleUseDescription format. For information on this format,
* (see <A HREF="http://ds.internic.net/rfc/rfc2252.txt"
* TARGET="_blank">RFC 2252, Lightweight Directory Access Protocol (v3):
* Attribute Syntax Definitions</A>. This is the format that LDAP servers
* and clients use to exchange schema information. For example, when
* you search an LDAP server for its schema, the server returns an entry
* with attributes that include "matchingrule" and "matchingruleuse".
* The values of these attributes are matching rule descriptions
* in this format.
* <P>
*
* @param use definition of the use of the matching rule in the
* MatchingRuleUseDescription format
*/
public LDAPMatchingRuleUseSchema( String use ) {
attrName = "matchingruleuse";
parseValue( use );
Vector v = (Vector)properties.get( "APPLIES" );
if ( v != null ) {
_attributes = new String[v.size()];
v.copyInto( _attributes );
v.removeAllElements();
}
}
/**
* Gets the list of the OIDs of the attribute types which can be used
* with the matching rule.
* @return array of the OIDs of the attribute types which can be used
* with the matching rule.
*/
public String[] getApplicableAttributes() {
return _attributes;
}
/**
* Gets the attribute name for a schema element
*
* @return The attribute name of the element
*/
String getAttributeName() {
return "matchingruleuse";
}
/**
* Gets the matching rule use definition in the string representation
* of the MatchingRuleUseDescription data type defined in X.501 (see
* <A HREF="http://ds.internic.net/rfc/rfc2252.txt"
* TARGET="_blank">RFC 2252, Lightweight Directory Access Protocol
* (v3): Attribute Syntax Definitions</A>
* for a description of these formats).
* This is the format that LDAP servers and clients use to exchange
* schema information. (For example, when
* you search an LDAP server for its schema, the server returns an entry
* with the attributes "matchingrules" and "matchingruleuse". The
* values of these attributes are matching rule description and
* matching rule use description in these formats.)
* <P>
*
* @return a string in a format that can be used as the value of
* the <CODE>matchingruleuse</CODE> attribute (which describes the use of
* a matching rule in the schema) of a <CODE>subschema</CODE> object
*/
public String getValue() {
String s = getValuePrefix();
if ( (_attributes != null) && (_attributes.length > 0) ) {
s += "APPLIES ( ";
for( int i = 0; i < _attributes.length; i++ ) {
if ( i > 0 )
s += " $ ";
s += _attributes[i];
}
s += " ) ";
}
s += ')';
return s;
}
/**
* Gets the definition of the matching rule use in Directory format
*
* @return definition of the matching rule use in Directory format
*/
public String toString() {
return getValue();
}
// Qualifiers tracked explicitly
static final String[] EXPLICIT = { OBSOLETE };
private String[] _attributes = null;
}

View File

@@ -0,0 +1,280 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
import org.ietf.ldap.client.opers.*;
import org.ietf.ldap.ber.stream.*;
import java.io.*;
import java.net.*;
/**
* Base class for LDAP request and response messages.
* This class represents the LDAPMessage in RFC2251. The
* message is the entity that got transferred back and
* fro between the server and the client interface. Each
* message has a protocol operation. The protocol operation
* indicates if it is a request or response.
* <pre>
* LDAPMessage ::= SEQUENCE {
* messageID MessageID,
* protocolOp CHOICE {
* bindRequest BindRequest,
* ...
* }
* controls [0] Controls OPTIONAL
* }
* </pre>
*
* @version 1.0
*/
public class LDAPMessage implements Serializable {
static final long serialVersionUID = -1364094245850026720L;
public final static int BIND_REQUEST = 0;
public final static int BIND_RESPONSE = 1;
public final static int UNBIND_REQUEST = 2;
public final static int SEARCH_REQUEST = 3;
public final static int SEARCH_RESPONSE = 4;
public final static int SEARCH_RESULT = 5;
public final static int MODIFY_REQUEST = 6;
public final static int MODIFY_RESPONSE = 7;
public final static int ADD_REQUEST = 8;
public final static int ADD_RESPONSE = 9;
public final static int DEL_REQUEST = 10;
public final static int DEL_RESPONSE = 11;
public final static int MODIFY_RDN_REQUEST = 12;
public final static int MODIFY_RDN_RESPONSE = 13;
public final static int COMPARE_REQUEST = 14;
public final static int COMPARE_RESPONSE = 15;
public final static int ABANDON_REQUEST = 16;
public final static int SEARCH_RESULT_REFERENCE = 19;
public final static int EXTENDED_REQUEST = 23;
public final static int EXTENDED_RESPONSE = 24;
/**
* Internal variables
*/
private int _msgid;
private JDAPProtocolOp _protocolOp = null;
private LDAPControl _controls[] = null;
/**
* Constructs a ldap message.
* @param msgid message identifier
* @param op operation protocol
*/
LDAPMessage(int msgid, JDAPProtocolOp op) {
_msgid = msgid;
_protocolOp = op;
}
LDAPMessage(int msgid, JDAPProtocolOp op, LDAPControl controls[]) {
_msgid = msgid;
_protocolOp = op;
_controls = controls; /* LDAPv3 additions */
}
/**
* Creates a ldap message from a BERElement. This method is used
* to parse LDAP response messages
*
* @param element ber element constructed from incoming byte stream
*/
static LDAPMessage parseMessage(BERElement element) throws IOException {
int l_msgid;
JDAPProtocolOp l_protocolOp = null;
LDAPControl l_controls[] = null;
if (element.getType() != BERElement.SEQUENCE)
throw new IOException("SEQUENCE in jdap message expected");
BERSequence seq = (BERSequence)element;
BERInteger msgid = (BERInteger)seq.elementAt(0);
l_msgid = msgid.getValue();
BERElement protocolOp = (BERElement)seq.elementAt(1);
if (protocolOp.getType() != BERElement.TAG) {
throw new IOException("TAG in protocol operation is expected");
}
BERTag tag = (BERTag)protocolOp;
switch (tag.getTag()&0x1f) {
case JDAPProtocolOp.BIND_RESPONSE:
l_protocolOp = new JDAPBindResponse(protocolOp);
break;
case JDAPProtocolOp.SEARCH_RESPONSE:
l_protocolOp = new JDAPSearchResponse(protocolOp);
break;
/*
* If doing search without bind,
* x500.arc.nasa.gov returns tag SEARCH_REQUEST tag
* in SEARCH_RESULT.
*/
case JDAPProtocolOp.SEARCH_REQUEST:
case JDAPProtocolOp.SEARCH_RESULT:
l_protocolOp = new JDAPSearchResult(protocolOp);
break;
case JDAPProtocolOp.MODIFY_RESPONSE:
l_protocolOp = new JDAPModifyResponse(protocolOp);
break;
case JDAPProtocolOp.ADD_RESPONSE:
l_protocolOp = new JDAPAddResponse(protocolOp);
break;
case JDAPProtocolOp.DEL_RESPONSE:
l_protocolOp = new JDAPDeleteResponse(protocolOp);
break;
case JDAPProtocolOp.MODIFY_RDN_RESPONSE:
l_protocolOp = new JDAPModifyRDNResponse(protocolOp);
break;
case JDAPProtocolOp.COMPARE_RESPONSE:
l_protocolOp = new JDAPCompareResponse(protocolOp);
break;
case JDAPProtocolOp.SEARCH_RESULT_REFERENCE:
l_protocolOp = new JDAPSearchResultReference(protocolOp);
break;
case JDAPProtocolOp.EXTENDED_RESPONSE:
l_protocolOp = new JDAPExtendedResponse(protocolOp);
break;
default:
throw new IOException("Unknown protocol operation");
}
/* parse control */
if (seq.size() >= 3) {
tag = (BERTag)seq.elementAt(2);
if ( tag.getTag() == (BERTag.CONSTRUCTED|BERTag.CONTEXT|0) ) {
BERSequence controls = (BERSequence)tag.getValue();
l_controls = new LDAPControl[controls.size()];
for (int i = 0; i < controls.size(); i++) {
l_controls[i] = LDAPControl.parseControl(controls.elementAt(i));
}
}
}
if (l_protocolOp instanceof JDAPSearchResponse) {
return new LDAPSearchResult(l_msgid,
(JDAPSearchResponse) l_protocolOp, l_controls);
}
else if (l_protocolOp instanceof JDAPSearchResultReference) {
return new LDAPSearchResultReference(l_msgid,
(JDAPSearchResultReference) l_protocolOp, l_controls);
}
else if (l_protocolOp instanceof JDAPExtendedResponse) {
return new LDAPExtendedResponse(l_msgid,
(JDAPExtendedResponse) l_protocolOp, l_controls);
}
else {
return new LDAPResponse(l_msgid, l_protocolOp, l_controls);
}
}
/**
* Retrieves list of controls.
* @return controls.
*/
public LDAPControl[] getControls() {
return (_controls != null) ? _controls : new LDAPControl[0];
}
/**
* Returns the message identifer.
* @return message identifer.
*/
public int getMessageID(){
return _msgid;
}
/**
* Returns the LDAP operation type of the message
* @return message type.
*/
public int getType(){
return _protocolOp.getType();
}
/**
* Retrieves the protocol operation.
* @return protocol operation.
*/
JDAPProtocolOp getProtocolOp() {
return _protocolOp;
}
/**
* Writes the ber encoding to stream.
* @param s output stream
*/
void write(OutputStream s) throws IOException {
BERSequence seq = new BERSequence();
BERInteger i = new BERInteger(_msgid);
seq.addElement(i);
BERElement e = _protocolOp.getBERElement();
if (e == null) {
throw new IOException("Bad BER element");
}
seq.addElement(e);
if (_controls != null) { /* LDAPv3 additions */
BERSequence c = new BERSequence();
for (int j = 0; j < _controls.length; j++) {
c.addElement(_controls[j].getBERElement());
}
BERTag t = new BERTag(BERTag.CONTEXT|BERTag.CONSTRUCTED|0, c, true);
seq.addElement(t);
}
seq.write(s);
}
/**
* Returns string representation of an LDAP message.
* @return LDAP message.
*/
public String toString() {
StringBuffer sb = new StringBuffer("[LDAPMessage] ");
sb.append(_msgid);
sb.append(" ");
sb.append(_protocolOp.toString());
for (int i =0; _controls != null && i < _controls.length; i++) {
sb.append(" ");
sb.append(_controls[i].toString());
}
return sb.toString();
}
/**
* Returns string representation of a ldap message with
* the time stamp. Used for message trace
* @return ldap message with the time stamp
*/
StringBuffer toTraceString() {
StringBuffer sb = new StringBuffer(" op=");
sb.append(_msgid);
sb.append(" ");
sb.append(_protocolOp.toString());
for (int i =0; _controls != null && i < _controls.length; i++) {
sb.append(" ");
sb.append(_controls[i].toString());
}
return sb;
}
}

View File

@@ -0,0 +1,116 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.io.Serializable;
import java.util.Vector;
/**
* A queue of response messsages from the server. Multiple requests
* can be multiplexed on the same queue. For synchronous LDAPConnection
* requests, there will be only one request per queue. For asynchronous
* LDAPConnection requests, the user can add multiple request to the
* same queue.
*
*/
public interface LDAPMessageQueue {
/**
* Returns the count of queued messages
* @return message count
*/
public int getMessageCount();
/**
* Returns a list of message IDs for all outstanding requests
* @return message ID array.
*/
public int[] getMessageIDs();
/**
* Blocks until a response is available or until all operations
* associated with the object have completed or been canceled
*
* @return LDAP message or null if there are no more outstanding requests.
* @exception LDAPException Network error exception
* @exception LDAPInterruptedException The invoking thread was interrupted
*/
public LDAPMessage getResponse() throws LDAPException;
/**
* Blocks until a response is available for a particular message ID, or
* until all operations associated with the message ID have completed or
* been canceled, and returns the response. If there is no outstanding
* operation for the message ID (or if it is zero or a negative number),
* IllegalArgumentException is thrown.
*
* @param msgid A particular message to query for responses available
* @return a response for an LDAP operation or null if there are no
* more outstanding requests.
* @exception LDAPException Network error exception
* @exception LDAPInterruptedException The invoking thread was interrupted
*/
public LDAPMessage getResponse( int msgid )
throws LDAPException;
/**
* Checks if a response message has been received
*
* @return true or false.
*/
public boolean isResponseReceived();
/**
* Reports true if a response has been received from the server for a
* particular message ID. If there is no outstanding operation for the
* message ID (or if it is zero or a negative number),
* IllegalArgumentException is thrown.
*
* @param msgid A particular message to query for responses available
* @return a flag indicating whether the response message queue is empty
*/
public boolean isResponseReceived( int msgid );
/**
* Merge two message queues.
* Move/append the content from another message queue to this one.
*
* To be used for synchronization of asynchronous LDAP operations where
* requests are sent by one thread but processed by another one
*
* A client may be implemented in such a way that one thread makes LDAP
* requests and calls l.getMessageIDs(), while another thread is
* responsible for
* processing of responses (call l.getResponse()). Both threads are using
* the same queue objects. In such a case, a race
* condition may occur, where a LDAP response message is retrieved and
* the request terminated (request ID removed) before the first thread
* has a chance to execute l.getMessageIDs().
* The proper way to handle this scenario is to create a separate queue
* for each new request, and after l.getMessageIDs() has been invoked,
* merge the
* new request with the existing one.
* @param mq2 message queue to merge with this one
*/
public void merge( LDAPMessageQueue mq2 );
}

View File

@@ -0,0 +1,663 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.io.Serializable;
import java.util.ArrayList;
/**
* A queue of response messsages from the server. Multiple requests
* can be multiplexed on the same queue. For synchronous LDAPConnection
* requests, there will be only one request per queue. For asynchronous
* LDAPConnection requests, the user can add multiple request to the
* same queue.
*
* Used as a delegate by LDAResponseListener and LDAPSearchListener
*
*/
class LDAPMessageQueueImpl implements Serializable, LDAPMessageQueue {
static final long serialVersionUID = -7163312406176592277L;
/**
* Request entry encapsulates request parameters
*/
private static class RequestEntry {
int id;
LDAPConnection connection;
LDAPConnThread connThread;
long timeToComplete;
RequestEntry( int id, LDAPConnection connection,
LDAPConnThread connThread, int timeLimit ) {
this.id = id;
this.connection = connection;
this.connThread = connThread;
this.timeToComplete = (timeLimit == 0) ?
Long.MAX_VALUE : (System.currentTimeMillis() + timeLimit);
}
}
/**
* Internal variables
*/
protected /*LDAPMessage */ ArrayList _messageQueue = new ArrayList(1);
private /*RequestEntry*/ ArrayList _requestList = new ArrayList(1);
private LDAPException _exception; /* For network errors */
private boolean _asynchOp;
// A flag to indicate if there are time constrained requests
private boolean _timeConstrained;
/**
* Constructor
*
* @param asynchOp <CODE>true</CODE> if the object is used
* for asynchronous LDAP operations
* @see org.ietf.ldap.LDAPAsynchronousConnection
*/
LDAPMessageQueueImpl( boolean asynchOp ) {
_asynchOp = asynchOp;
}
/**
* Returns the count of queued messages
*
* @return message count
*/
public int getMessageCount() {
return _messageQueue.size();
}
/**
* Returns a list of message IDs for all outstanding requests
*
* @return message ID array
*/
synchronized public int[] getMessageIDs() {
int[] ids = new int[_requestList.size()];
for ( int i = 0; i < ids.length; i++ ) {
RequestEntry entry = (RequestEntry)_requestList.get(i);
ids[i] = entry.id;
}
return ids;
}
/**
* Blocks until a message is available or until all operations
* associated with the object have completed or been canceled
*
* @return LDAP message or null if there are no more outstanding requests
* @exception LDAPException Network error exception
* @exception LDAPInterruptedException The invoking thread was interrupted
*/
public synchronized LDAPMessage getResponse() throws LDAPException {
while( true ) {
if ( !waitForSomething() ) {
return null; // No outstanding requests
}
// Dequeue the first entry
LDAPMessage msg = (LDAPMessage)_messageQueue.get( 0 );
_messageQueue.remove( 0 );
// Has the operation completed?
if ( msg instanceof LDAPResponse ) {
removeRequest( msg.getMessageID() );
}
return msg;
}
}
/**
* Blocks until a message is available for a particular message ID, or
* until all operations associated with the message ID have completed or
* been canceled, and returns the response. If there is no outstanding
* operation for the message ID (or if it is zero or a negative number),
* IllegalArgumentException is thrown.
*
* @param msgid A particular message to query for responses available
* @return a response for an LDAP operation or null if there are no
* more outstanding requests.
* @exception LDAPException Network error exception
* @exception LDAPInterruptedException The invoking thread was interrupted
*/
public synchronized LDAPMessage getResponse( int msgid )
throws LDAPException {
if ( !isValidMessageID( msgid ) ) {
throw new IllegalArgumentException( "Invalid msg ID: " + msgid );
}
LDAPMessage msg = null;
while( ( _requestList.size() != 0 ) &&
( _exception == null ) &&
( (msg = getMessageForID( msgid, true )) == null ) ) {
waitForMessage();
}
// Network exception occurred?
if ( _exception != null ) {
LDAPException ex = _exception;
_exception = null;
throw ex;
}
// Are there any outstanding requests left?
if ( _requestList.size() == 0 ) {
return null; // No outstanding requests
}
// Has the operation completed?
if ( msg instanceof LDAPResponse ) {
removeRequest( msg.getMessageID() );
}
return msg;
}
/**
* Checks if a response message has been received
*
* @return true or false
*/
public boolean isResponseReceived() {
return ( _messageQueue.size() != 0 );
}
/**
* Reports true if a response has been received from the server for a
* particular message ID. If there is no outstanding operation for the
* message ID (or if it is zero or a negative number),
* IllegalArgumentException is thrown.
*
* @param msgid A particular message to query for responses available
* @return a flag indicating whether the response message queue is empty
*/
public boolean isResponseReceived( int msgid ) {
if ( !isValidMessageID( msgid ) ) {
throw new IllegalArgumentException( "Invalid msg ID: " + msgid );
}
return ( getMessageForID( msgid, false ) != null );
}
/**
* Merge two message queues.
* Move/append the content from another message queue to this one.
*
* To be used for synchronization of asynchronous LDAP operations where
* requests are sent by one thread but processed by another one
*
* A client may be implemented in such a way that one thread makes LDAP
* requests and calls l.getMessageIDs(), while another thread is
* responsible for
* processing of responses (call l.getResponse()). Both threads are using
* the same listener objects. In such a case, a race
* condition may occur, where a LDAP response message is retrieved and
* the request terminated (request ID removed) before the first thread
* has a chance to execute l.getMessageIDs().
* The proper way to handle this scenario is to create a separate listener
* for each new request, and after l.getMessageIDs() has been invoked,
* merge the
* new request with the existing one.
* @param mq2 message queue to merge with this one
*/
public void merge( LDAPMessageQueue mq2 ) {
// Yield just in case the LDAPConnThread is in the process of
// dispatching a message
Thread.yield();
synchronized( this ) {
LDAPMessageQueueImpl mq = (LDAPMessageQueueImpl)mq2;
synchronized( mq ) {
ArrayList queue2 = mq.getAllMessages();
for( int i = 0; i < queue2.size(); i++ ) {
_messageQueue.add( queue2.get( i ) );
}
if ( mq.getException() != null ) {
_exception = mq.getException();
}
ArrayList list2 = mq.getAllRequests();
for( int i = 0; i < list2.size(); i++ ) {
RequestEntry entry = (RequestEntry)list2.get( i );
_requestList.add( entry );
// Notify LDAPConnThread to redirect mq2 designated
// responses to this mq
entry.connThread.changeQueue( entry.id, this );
}
mq.reset();
notifyAll(); // notify for mq2
}
notifyAll(); // notify this mq
}
}
/**
* Gets String representation of the object
*
* @return String representation of the object
*/
synchronized public String toString() {
StringBuffer sb = new StringBuffer( "LDAPMessageQueueImpl:" );
sb.append(" requestIDs={");
for ( int i = 0; i < _requestList.size(); i++ ) {
if ( i > 0 ) {
sb.append( "," );
}
sb.append( ((RequestEntry)_requestList.get(i)).id );
}
sb.append( "} messageCount=" + _messageQueue.size() );
return sb.toString();
}
/**
* Retrieves the next response for a particular message ID, or null
* if there is none
*
* @param msgid A particular message to query for responses available
* @param remove <code>true</code> if the retrieved message is to be
* removed from the queue
* @return a flag indicating whether the response message queue is empty
*/
synchronized LDAPMessage getMessageForID( int msgid, boolean remove ) {
LDAPMessage msg = null;
for ( int i = 0; i < _messageQueue.size(); i++ ) {
msg = (LDAPMessage)_messageQueue.get(i);
if ( msg.getMessageID() == msgid ) {
if ( remove ) {
_messageQueue.remove( i );
}
break;
}
}
return msg;
}
/**
* Reports if the listener is used for asynchronous LDAP
* operations
*
* @return asynchronous operation flag.
* @see org.ietf.ldap.LDAPAsynchronousConnection
*/
boolean isAsynchOp() {
return _asynchOp;
}
/**
* Waits for request to complete. This method blocks until a message of
* type LDAPResponse has been received. Used by synchronous search
* with batch size of zero (block until all results are received).
*
* @return LDAPResponse message or null if there are no more outstanding
* requests
* @exception LDAPException Network error exception
* @exception LDAPInterruptedException The invoking thread was interrupted
*/
synchronized LDAPResponse completeRequest() throws LDAPException {
while ( true ) {
if ( !waitForSomething() ) {
return null; // No outstanding requests
}
// Search for an instance of LDAPResponse
for ( int i = _messageQueue.size()-1; i >= 0; i-- ) {
Object msg = _messageQueue.get(i);
if ( msg instanceof LDAPResponse ) {
// Dequeue the entry and return
_messageQueue.remove( i );
return (LDAPResponse)msg;
}
}
// Not found, wait for the next message
}
}
/**
* Waits for any message. Processes interrupts and honors
* time limit if set for any request.
*/
synchronized private void waitForMessage() throws LDAPException {
if ( !_timeConstrained ) {
try {
wait();
return;
} catch (InterruptedException e) {
throw new LDAPInterruptedException(
"Interrupted LDAP operation" );
}
}
/**
* Perform time constrained wait
*/
long minTimeToComplete = Long.MAX_VALUE;
long now = System.currentTimeMillis();
for ( int i = 0; i < _requestList.size(); i++ ) {
RequestEntry entry = (RequestEntry)_requestList.get( i );
// time limit exceeded ?
if ( entry.timeToComplete <= now ) {
entry.connection.abandon( entry.id );
throw new LDAPException( "Time to complete operation exceeded",
LDAPException.LDAP_TIMEOUT );
}
if ( entry.timeToComplete < minTimeToComplete ) {
minTimeToComplete = entry.timeToComplete;
}
}
long timeLimit = ( minTimeToComplete == Long.MAX_VALUE ) ?
0 : ( minTimeToComplete - now );
try {
_timeConstrained = ( timeLimit != 0 );
wait( timeLimit );
} catch ( InterruptedException e ) {
throw new LDAPInterruptedException( "Interrupted LDAP operation" );
}
}
/**
* Waits for a message, for the request list to be empty, or for
* an exception
*
* @return <CODE>true</CODE> if the request list is not empty
* @exception LDAPException Network error
*/
boolean waitForSomething() throws LDAPException {
while( (_requestList.size() != 0) &&
(_exception == null) &&
(_messageQueue.size() == 0) ) {
waitForMessage();
}
// Network exception occurred ?
if ( _exception != null ) {
LDAPException ex = _exception;
_exception = null;
throw ex;
}
// Are there any outstanding requests left
if ( _requestList.size() == 0 ) {
return false; // No outstanding requests
}
return true;
}
/**
* Retrieves all messages currently in the queue without blocking.
* The messages are removed from the queue.
*
* @return vector of messages
*/
synchronized ArrayList getAllMessages() {
ArrayList result = _messageQueue;
_messageQueue = new ArrayList(1);
return result;
}
/**
* Retrieves all requests currently in the queue.
* The requests are removed from the queue.
*
* @return vector of requests
*/
synchronized ArrayList getAllRequests() {
ArrayList result = _requestList;
_requestList = new ArrayList(1);
return result;
}
/**
* Queues the LDAP server's response. This causes anyone waiting
* in getResponse() to unblock.
*
* @param msg response message
*/
synchronized void addMessage( LDAPMessage msg ) {
_messageQueue.add(msg);
// Mark conn as bound for asych bind operations
if ( isAsynchOp() &&
(msg.getType() == msg.BIND_RESPONSE) ) {
if ( ((LDAPResponse)msg).getResultCode() == 0 ) {
getConnection( msg.getMessageID() ).markConnAsBound();
}
}
notifyAll();
}
/**
* Gets a possible exception from the queue
*
* @return a possibly null exception
*/
LDAPException getException() {
return _exception;
}
/**
* Reports if the message ID is in the request list
*
* @param msgid The message ID to validate
* @return <CODE>true</CODE> if the message ID is in the request list
*/
synchronized boolean isValidMessageID( int msgid ) {
return ( getRequestEntry( msgid ) != null );
}
/**
* Signals that a network exception occured while servicing the
* request. This exception will be throwm to any thread waiting
* in getResponse().
*
* @param connThread LDAPConnThread on which the exception occurred
* @param e exception
*/
synchronized void setException( LDAPConnThread connThread,
LDAPException e ) {
_exception = e;
removeAllRequests( connThread );
notifyAll();
}
/**
* Remove all queued messages associated with the request ID.
* Called when an LDAP operation is abandoned.
*
* Not synchronized as it is private and can be called only by
* abandon() and removeAllRequests().
*
* @return count of removed messages
*/
private int removeAllMessages( int id ) {
int removeCount = 0;
for ( int i = (_messageQueue.size()-1); i >= 0; i-- ) {
LDAPMessage msg = (LDAPMessage)_messageQueue.get( i );
if ( msg.getMessageID() == id ) {
_messageQueue.remove( i );
removeCount++;
}
}
return removeCount;
}
/**
* Resets the state of this object so it can be recycled.
* Used by LDAPConnection synchronous operations.
*
* @see org.ietf.ldap.LDAPConnection#getResponseListener
* @see org.ietf.ldap.LDAPConnection#getSearchListener
*/
void reset() {
_exception = null;
_messageQueue.clear();
_requestList.clear();
_timeConstrained = false;
}
/**
* Returns the connection associated with the specified request id
*
* @param id request id
* @return connection
*/
synchronized LDAPConnection getConnection( int id ) {
RequestEntry entry = getRequestEntry( id );
if ( entry != null ) {
return entry.connection;
}
return null;
}
/**
* Returns the connection thread associated with the specified request id
*
* @param id request id
* @return connection thread
*/
synchronized LDAPConnThread getConnThread( int id ) {
RequestEntry entry = getRequestEntry( id );
if ( entry != null ) {
return entry.connThread;
}
return null;
}
/**
* Returns the request entry associated with the specified request id
*
* @param id request id
* @return request entry or null
*/
synchronized RequestEntry getRequestEntry( int id ) {
for ( int i = 0; i < _requestList.size(); i++ ) {
RequestEntry entry = (RequestEntry)_requestList.get( i );
if ( id == entry.id ) {
return entry;
}
}
return null;
}
/**
* Returns message ID of the last request
*
* @return message ID
*/
synchronized int getMessageID() {
int reqCnt = _requestList.size();
if ( reqCnt == 0 ) {
return -1;
} else {
RequestEntry entry =
(RequestEntry)_requestList.get( reqCnt-1 );
return entry.id;
}
}
/**
* Registers an LDAP request
*
* @param id LDAP request message ID
* @param connection LDAP Connection for the message ID
* @param connThread a physical connection to the server
* @param timeLimit the maximum number of milliseconds to wait for
* the request to complete
*/
synchronized void addRequest( int id, LDAPConnection connection,
LDAPConnThread connThread, int timeLimit ) {
_requestList.add( new RequestEntry( id, connection,
connThread, timeLimit ) );
if ( timeLimit != 0 ) {
_timeConstrained = true;
}
notifyAll();
}
/**
* Returns the number of outstanding requests.
* @return outstanding request count.
*/
public int getRequestCount() {
return _requestList.size();
}
/**
* Removes the request with the specified ID.
* Called when a LDAP operation is abandoned (called from
* LDAPConnThread), or terminated (called by getResponse() when
* LDAPResponse message is received).
*
* @return flag indicating if the request was removed
*/
synchronized boolean removeRequest( int id ) {
for ( int i = 0; i < _requestList.size(); i++ ) {
RequestEntry entry = (RequestEntry)_requestList.get( i );
if ( id == entry.id ) {
_requestList.remove( i );
removeAllMessages( id );
notifyAll();
return true;
}
}
return false;
}
/**
* Removes all requests associated with the specified connThread.
* Called when a connThread has a network error.
*
* @return number of removed requests
*/
synchronized int removeAllRequests( LDAPConnThread connThread ) {
int removeCount = 0;
for ( int i = (_requestList.size()-1); i >= 0; i-- ) {
RequestEntry entry = (RequestEntry)_requestList.get( i );
if ( connThread == entry.connThread ) {
_requestList.remove( i );
removeCount++;
// remove all queued messages as well
removeAllMessages( entry.id );
}
}
notifyAll();
return removeCount;
}
}

View File

@@ -0,0 +1,150 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.io.Serializable;
import org.ietf.ldap.ber.stream.*;
/**
* Specifies changes to be made to the values of an attribute. The change is
* specified in terms of the following aspects:
* <P>
*
* <UL>
* <LI>the type of modification (add, replace, or delete the value of an attribute)
* <LI>the type of value being modified (string or binary)
* <LI>the name of the attribute being modified
* <LI>the actual value
* </UL>
* <P>
*
* After you specify a change to an attribute, you can execute the change
* by calling the <CODE>LDAPConnection.modify</CODE> method and specifying
* the DN of the entry that you want to modify.
* <P>
*
* @version 1.0
* @see org.ietf.ldap.LDAPConnection#modify(java.lang.String, org.ietf.ldap.LDAPModification)
*/
public class LDAPModification implements Serializable {
static final long serialVersionUID = 4836472112866826595L;
/**
* Specifies that a value should be added to an attribute.
*/
public static final int ADD = 0;
/**
* Specifies that a value should be removed from an attribute.
*/
public static final int DELETE = 1;
/**
* Specifies that a value should replace the existing value in an attribute.
*/
public static final int REPLACE = 2;
/**
* Internal variables
*/
private int operation;
private LDAPAttribute attribute;
/**
* Specifies a modification to be made to an attribute.
* @param op the type of modification to make. This can be one of the following:
* <P>
* <UL>
* <LI><CODE>LDAPModification.ADD</CODE> (the value should be added to the attribute)
* <LI><CODE>LDAPModification.DELETE</CODE> (the value should be removed from the attribute)
* <LI><CODE>LDAPModification.REPLACE</CODE> (the value should replace the existing value of the attribute)
* </UL><P>
* @param attr the attribute (possibly with values) to modify
* @see org.ietf.ldap.LDAPAttribute
*/
public LDAPModification( int op, LDAPAttribute attr ) {
operation = op;
attribute = attr;
}
/**
* Returns the attribute (possibly with values) to be modified.
* @return the attribute to be modified.
* @see org.ietf.ldap.LDAPAttribute
*/
public LDAPAttribute getAttribute() {
return attribute;
}
/**
* Returns the type of modification specified by this object.
* @return one of the following types of modifications:
* <P>
* <UL>
* <LI><CODE>LDAPModification.ADD</CODE> (the value should be added to the attribute)
* <LI><CODE>LDAPModification.DELETE</CODE> (the value should be removed from the attribute)
* <LI><CODE>LDAPModification.REPLACE</CODE> (the value should replace the existing value of the attribute)
* </UL><P>
*/
public int getOp() {
return operation;
}
/**
* Retrieves the BER (Basic Encoding Rules) representation
* of the current modification.
* @return BER representation of the modification.
*/
public BERElement getBERElement() {
BERSequence seq = new BERSequence();
seq.addElement(new BEREnumerated(operation));
seq.addElement(attribute.getBERElement());
return seq;
}
/**
* Retrieves the string representation of the current
* modification. For example:
*
* <PRE>
* LDAPModification: REPLACE, LDAPAttribute {type='mail', values='babs@ace.com'}
* LDAPModification: ADD, LDAPAttribute {type='description', values='This entry was modified with the modattrs program'}
* </PRE>
*
* @return string representation of the current modification.
*/
public String toString() {
String s = "LDAPModification: ";
if ( operation == ADD )
s += "ADD, ";
else if ( operation == DELETE )
s += "DELETE, ";
else if ( operation == REPLACE )
s += "REPLACE, ";
else
s += "INVALID OP, ";
s += attribute;
return s;
}
}

View File

@@ -0,0 +1,287 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
/**
* The definition of a name form in the schema.
* <A HREF="http://ds.internic.net/rfc/rfc2252.txt"
* TARGET="_blank">RFC 2252, Lightweight Directory Access Protocol (v3):
* Attribute Syntax Definitions</A> covers the types of information
* that need to be specified in the definition of a name form.
* According to the RFC, the description of a name form can
* include the following information:
* <P>
*
* <UL>
* <LI>an OID identifying the name form
* <LI>a name identifying the name form
* <LI>a description of the name form
* <LI>the structural object class of this name form
* <LI>the list of attribute types that are required in this name form
* <LI>the list of attribute types that are allowed (optional) in this
* name form
* </UL>
* <P>
*
* When you construct an <CODE>LDAPNameFormSchema</CODE> object,
* you can specify
* these types of information as arguments to the constructor or in the
* NameFormDescription format specified in RFC 2252.
* When an LDAP client searches an LDAP server for the schema, the server
* returns schema information as an object with attribute values in this
* format.
* <P>
*
* You can get the name, OID, and description of this name form
* definition by using the <CODE>getName</CODE>, <CODE>getOID</CODE>, and
* <CODE>getDescription</CODE> methods inherited from the abstract class
* <CODE>LDAPSchemaElement</CODE>. Optional and custom qualifiers are
* accessed with <CODE>getQualifier</CODE> and <CODE>getQualifierNames</CODE>
* from <CODE>LDAPSchemaElement</CODE>.
* <P>
*
* To add or remove this name form definition from the
* schema, use the <CODE>add</CODE> and <CODE>remove</CODE>
* methods, which this class inherits from the <CODE>LDAPSchemaElement</CODE>
* abstract class.
* <P>
* RFC 2252 defines NameFormDescription as follows:
* <P>
* <PRE>
* NameFormDescription = "(" whsp
* numericoid whsp ; NameForm identifier
* [ "NAME" qdescrs ]
* [ "DESC" qdstring ]
* [ "OBSOLETE" whsp ]
* "OC" woid ; Structural ObjectClass
* [ "MUST" oids ] ; AttributeTypes
* [ "MAY" oids ] ; AttributeTypes
* whsp ")"
* </PRE>
*
* @version 1.0
* @see org.ietf.ldap.LDAPSchemaElement
**/
public class LDAPNameFormSchema extends LDAPSchemaElement {
static final long serialVersionUID = 1665316286199590403L;
/**
* Constructs a name form definition, using the specified
* information.
* @param names name of the name form
* @param oid object identifier (OID) of the name form
* in dotted-string format (for example, "1.2.3.4")
* @param description description of the name form
* @param obsolete <code>true</code> if the rule is obsolete
* @param objectClass the object to which this name form applies.
* This may either be specified by name or numeric oid.
* @param required array of names of attributes required
* in this name form
* @param optional array of names of optional attributes
* allowed in this name form
*/
public LDAPNameFormSchema( String[] names,
String oid,
String description,
boolean obsolete,
String objectClass,
String[] required,
String[] optional ) {
super( names, oid, description );
attrName = "nameforms";
if ( obsolete ) {
setQualifier( OBSOLETE, "" );
}
this.objectClass = objectClass;
if ( required != null ) {
for( int i = 0; i < required.length; i++ ) {
must.addElement( required[i] );
}
}
if ( optional != null ) {
for( int i = 0; i < optional.length; i++ ) {
may.addElement( optional[i] );
}
}
}
/**
* Constructs a name form definition based on a description in
* the NameFormDescription format. For information on this format,
* (see <A HREF="http://ds.internic.net/rfc/rfc2252.txt"
* TARGET="_blank">RFC 2252, Lightweight Directory Access Protocol (v3):
* Attribute Syntax Definitions</A>. This is the format that LDAP servers
* and clients use to exchange schema information. (For example, when
* you search an LDAP server for its schema, the server returns an entry
* with the attributes "objectclasses" and "attributetypes". The
* values of the "objectclasses" attribute are name form descriptions
* in this format.)
* <P>
*
* @param raw definition of the object in the NameFormDescription
* format
*/
public LDAPNameFormSchema( String raw ) {
attrName = "objectclasses";
parseValue( raw );
Object o = properties.get( "MAY" );
if ( o != null ) {
if ( o instanceof Vector ) {
may = (Vector)o;
} else {
may.addElement( o );
}
}
o = properties.get( "MUST" );
if ( o != null ) {
if ( o instanceof Vector ) {
must = (Vector)o;
} else {
must.addElement( o );
}
}
o = properties.get( "OC" );
if ( o != null ) {
objectClass = (String)o;
}
}
/**
* Returns the name of the object class that this name form applies to.
*
* @return the name of the object class that this name form applies to.
*/
public String getObjectClass() {
return objectClass;
}
/**
* Gets the names of optional attributes allowed
* in this name form.
* @return the names of optional attributes
* allowed in this name form.
*/
public String[] getOptionalNamingAttributes() {
String[] vals = new String[may.size()];
may.copyInto( vals );
return vals;
}
/**
* Gets the names of the required attributes for
* this name form.
* @return the names of the required attributes
* for this name form.
*/
public String[] getRequiredNamingAttributes() {
String[] vals = new String[must.size()];
must.copyInto( vals );
return vals;
}
/**
* Gets the attribute name for a schema element
*
* @return The attribute name of the element
*/
String getAttributeName() {
return "nameforms";
}
/**
* Prepares a value in RFC 2252 format for submitting to a server.
*
* @param quotingBug <CODE>true</CODE> if SUP and SYNTAX values are to
* be quoted. That is to satisfy bugs in certain LDAP servers.
* @return a String ready for submission to an LDAP server.
*/
String getValue( boolean quotingBug ) {
String s = getValuePrefix();
String val = getOptionalValues( NOVALS );
if ( val.length() > 0 ) {
s += val + ' ';
}
s += "OC " + objectClass + ' ';
if ( must.size() > 0 ) {
s += "MUST " + vectorToList( must );
s += ' ';
}
if ( may.size() > 0 ) {
s += "MAY " + vectorToList( may );
s += ' ';
}
val = getCustomValues();
if ( val.length() > 0 ) {
s += val + ' ';
}
s += ')';
return s;
}
/**
* Gets the definition of the name form in Directory format
*
* @return definition of the name form in Directory format
*/
public String toString() {
return getValue( false );
}
/**
* Creates a list within parentheses, with $ as delimiter
*
* @param vals values for list
* @return a String with a list of values.
*/
protected String vectorToList( Vector vals ) {
String val = "( ";
for( int i = 0; i < vals.size(); i++ ) {
val += (String)vals.elementAt(i) + ' ';
if ( i < (vals.size() - 1) ) {
val += "$ ";
}
}
val += ')';
return val;
}
private Vector must = new Vector();
private Vector may = new Vector();
private String objectClass = null;
// Qualifiers known to not have values; prepare a Hashtable
static final String[] NOVALS = { "OBSOLETE" };
static {
for( int i = 0; i < NOVALS.length; i++ ) {
novalsTable.put( NOVALS[i], NOVALS[i] );
}
}
// Qualifiers which we output explicitly in toString()
static final String[] IGNOREVALS = { "MUST", "MAY",
"OBJECTCLASS", "OBSOLETE"};
}

View File

@@ -0,0 +1,350 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
/**
* The definition of an object class in the schema.
* <A HREF="http://ds.internic.net/rfc/rfc2252.txt"
* TARGET="_blank">RFC 2252, Lightweight Directory Access Protocol (v3):
* Attribute Syntax Definitions</A> covers the types of information
* that need to be specified in the definition of an object class.
* According to the RFC, the description of an object class can
* include the following information:
* <P>
*
* <UL>
* <LI>an OID identifying the object class
* <LI>a name identifying the object class
* <LI>a description of the object class
* <LI>the name of the parent object class
* <LI>the list of attribute types that are required in this object class
* <LI>the list of attribute types that are allowed (optional) in this
* object class
* </UL>
* <P>
*
* When you construct an <CODE>LDAPObjectSchema</CODE> object, you can specify
* these types of information as arguments to the constructor or in the
* ObjectClassDescription format specified in RFC 2252.
* When an LDAP client searches an LDAP server for the schema, the server
* returns schema information as an object with attribute values in this
* format.
* <P>
*
* RFC 2252 also notes that you can specify whether or not an object class
* is abstract, structural, or auxiliary in the object description.
* Abstract object classes are used only to derive other object classes.
* Entries cannot belong to an abstract object class. <CODE>top</CODE>
* is an abstract object class. Entries must belong to a structural
* object class, so most object classes are structural object classes.
* Objects of the <CODE>LDAPObjectClassSchema</CODE> class are structural
* object classes by default. Auxiliary object classes can be used to
* add attributes to entries of different types. For example, an
* auxiliary object class might be used to specify personal preference
* attributes. An entry can not contain just that object class, but may
* include it along with a structural object class, for example
* inetOrgPerson.
* If the definition of an object (in ObjectClassDescription format)
* specifies the AUXILIARY keyword, an <CODE>LDAPObjectClassSchema</CODE>
* object created from that description represents an auxiliary object class.
* <P>
*
* You can get the name, OID, and description of this object class
* definition by using the <CODE>getName</CODE>, <CODE>getOID</CODE>, and
* <CODE>getDescription</CODE> methods inherited from the abstract class
* <CODE>LDAPSchemaElement</CODE>. Optional and custom qualifiers are
* accessed with <CODE>getQualifier</CODE> and <CODE>getQualifierNames</CODE>
* from <CODE>LDAPSchemaElement</CODE>.
* <P>
*
* To add or remove this object class definition from the
* schema, use the <CODE>add</CODE> and <CODE>remove</CODE>
* methods, which this class inherits from the <CODE>LDAPSchemaElement</CODE>
* abstract class.
* <P>
* RFC 2252 defines ObjectClassDescription as follows:
* <P>
* <PRE>
* ObjectClassDescription = "(" whsp
* numericoid whsp ; ObjectClass identifier
* [ "NAME" qdescrs ]
* [ "DESC" qdstring ]
* [ "OBSOLETE" whsp ]
* [ "SUP" oids ] ; Superior ObjectClasses
* [ ( "ABSTRACT" / "STRUCTURAL" / "AUXILIARY" ) whsp ]
* ; default structural
* [ "MUST" oids ] ; AttributeTypes
* [ "MAY" oids ] ; AttributeTypes
* whsp ")"
* </PRE>
*
* @version 1.0
* @see org.ietf.ldap.LDAPSchemaElement
**/
public class LDAPObjectClassSchema extends LDAPSchemaElement {
static final long serialVersionUID = -1732784695071118656L;
/**
* Constructs an object class definition, using the specified
* information.
* @param names names of the object class
* @param oid object identifier (OID) of the object class
* in dotted-string format (for example, "1.2.3.4")
* @param description description of the object class
* @param superiors names of parent object classes
* (the object classes that this object class inherits from)
* @param required array of names of attributes required
* in this object class
* @param optional array of names of optional attributes
* allowed in this object class
* @param type either ABSTRACT, STRUCTURAL, or AUXILIARY
* @param obsolete <code>true</code> if the rule is obsolete
*/
public LDAPObjectClassSchema( String[] names,
String oid,
String[] superiors,
String description,
String[] required,
String[] optional,
int type,
boolean obsolete ) {
super( names, oid, description );
attrName = "objectclasses";
setQualifier( SUPERIOR, superiors );
if ( required != null ) {
for( int i = 0; i < required.length; i++ ) {
must.addElement( required[i] );
}
}
if ( optional != null ) {
for( int i = 0; i < optional.length; i++ ) {
may.addElement( optional[i] );
}
}
if ( (superiors != null) && (superiors.length > 1) ) {
setQualifier( SUPERIOR, superiors );
}
if ( obsolete ) {
setQualifier( OBSOLETE, "" );
}
}
/**
* Constructs an object class definition based on a description in
* the ObjectClassDescription format. For information on this format,
* (see <A HREF="http://ds.internic.net/rfc/rfc2252.txt"
* TARGET="_blank">RFC 2252, Lightweight Directory Access Protocol (v3):
* Attribute Syntax Definitions</A>. This is the format that LDAP servers
* and clients use to exchange schema information. (For example, when
* you search an LDAP server for its schema, the server returns an entry
* with the attributes "objectclasses" and "attributetypes". The
* values of the "objectclasses" attribute are object class descriptions
* in this format.)
* <P>
*
* @param raw definition of the object in the ObjectClassDescription
* format
*/
public LDAPObjectClassSchema( String raw ) {
attrName = "objectclasses";
parseValue( raw );
setQualifier( TYPE, typeToString( getType() ) );
Object o = properties.get( "MAY" );
if ( o != null ) {
if ( o instanceof Vector ) {
may = (Vector)o;
} else {
may.addElement( o );
}
}
o = properties.get( "MUST" );
if ( o != null ) {
if ( o instanceof Vector ) {
must = (Vector)o;
} else {
must.addElement( o );
}
}
}
/**
* Gets an enumeration of names of optional attributes allowed
* in this object class.
* @return an enumeration of the names of optional attributes
* allowed in this object class.
*/
public Enumeration getOptionalAttributes() {
return may.elements();
}
/**
* Gets an enumeration of the names of the required attributes for
* this object class.
* @return an enumeration of the names of the required attributes
* for this object class.
*/
public Enumeration getRequiredAttributes() {
return must.elements();
}
/**
* Gets the names of all object classes that this class inherits
* from. Typically only one, but RFC 2252 allows multiple
* inheritance.
* @return the names of the object classes from which this class
* inherits.
*/
public String[] getSuperiors() {
return getQualifier( SUPERIOR );
}
/**
* Gets the type of the object class.
* @return STRUCTURAL, ABSTRACT, or AUXILIARY.
*/
public int getType() {
int type = STRUCTURAL;
if ( properties.containsKey( "AUXILIARY" ) ) {
type = AUXILIARY;
} else if ( properties.containsKey( "ABSTRACT" ) ) {
type = ABSTRACT;
}
return type;
}
/**
* Prepares a value in RFC 2252 format for submitting to a server.
*
* @param quotingBug <CODE>true</CODE> if SUP and SYNTAX values are to
* be quoted. That is to satisfy bugs in certain LDAP servers.
* @return a String ready for submission to an LDAP server.
*/
String getValue( boolean quotingBug ) {
String s = getValuePrefix();
String val = getValue( SUPERIOR, quotingBug );
if ( (val != null) && (val.length() > 0) ) {
s += val + ' ';
}
String[] vals = getQualifier( TYPE );
if ( (vals != null) && (vals.length > 0) ) {
s += vals[0] + ' ';
}
val = getOptionalValues( NOVALS );
if ( val.length() > 0 ) {
s += val + ' ';
}
if ( must.size() > 0 ) {
s += "MUST " + vectorToList( must );
s += ' ';
}
if ( may.size() > 0 ) {
s += "MAY " + vectorToList( may );
s += ' ';
}
val = getCustomValues();
if ( val.length() > 0 ) {
s += val + ' ';
}
s += ')';
return s;
}
/**
* Gets the definition of the object class in Directory format
*
* @return definition of the object class in Directory format
*/
public String toString() {
return getValue();
}
/**
* Gets the attribute name for a schema element
*
* @return The attribute name of the element
*/
String getAttributeName() {
return "objectclasses";
}
/**
* Creates a list within parentheses, with $ as delimiter
*
* @param vals values for list
* @return a String with a list of values.
*/
protected String vectorToList( Vector vals ) {
String val = "( ";
for( int i = 0; i < vals.size(); i++ ) {
val += (String)vals.elementAt(i) + ' ';
if ( i < (vals.size() - 1) ) {
val += "$ ";
}
}
val += ')';
return val;
}
/**
* Returns the object class type as a String
*
* @param type one of STRUCTURAL, ABSTRACT, or AUXILIARY
* @return one of "STRUCTURAL", "ABSTRACT", "AUXILIARY", or <CODE>null</CODE>
*/
protected String typeToString( int type ) {
switch( type ) {
case STRUCTURAL: return "STRUCTURAL";
case ABSTRACT: return "ABSTRACT";
case AUXILIARY: return "AUXILIARY";
default: return null;
}
}
public static final int STRUCTURAL = 0;
public static final int ABSTRACT = 1;
public static final int AUXILIARY = 2;
private Vector must = new Vector();
private Vector may = new Vector();
private int type = STRUCTURAL;
// Qualifiers known to not have values; prepare a Hashtable
static final String[] NOVALS = { "ABSTRACT", "STRUCTURAL",
"AUXILIARY", "OBSOLETE" };
static {
for( int i = 0; i < NOVALS.length; i++ ) {
novalsTable.put( NOVALS[i], NOVALS[i] );
}
}
// Qualifiers which we output explicitly in toString()
static final String[] IGNOREVALS = { "ABSTRACT", "STRUCTURAL",
"AUXILIARY", "MUST", "MAY",
"SUP", "OBSOLETE"};
// Key for type in the properties Hashtable
static final String TYPE = "TYPE";
}

View File

@@ -0,0 +1,213 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
//import org.ietf.ldap.client.*;
//import org.ietf.ldap.client.opers.*;
//import java.io.*;
/**
* Represents the situation in which the LDAP server refers the client to
* another LDAP server. This exception constructs a list of referral URLs from
* the LDAP error message returned by the server. You can get this list by
* using the <CODE>getURLs</CODE> method.
*
* @version 1.0
* @see org.ietf.ldap.LDAPException
*/
public class LDAPReferralException extends LDAPException {
static final long serialVersionUID = 1771536577344289897L;
private String _referrals[] = null;
/**
* Constructs a default exception with no specific error information.
*/
public LDAPReferralException() {
}
/**
* Constructs a default exception with a specified string as
* additional information. This form is used for lower-level errors.
* @param message the additional error information
*/
public LDAPReferralException( String message ) {
super( message );
}
/**
* Constructs a default exception with a specified string as
* additional information. This form is used for higher-level LDAP
* operational errors.
* @param message the additional error information
* @param resultCode result code
* @param serverErrorMessage error message
*/
public LDAPReferralException( String message,
int resultCode,
String serverErrorMessage ) {
super(message, resultCode, serverErrorMessage);
}
/**
* Constructs an exception with a list of LDAP URLs to other LDAP servers.
* This list of referrals points the client to LDAP servers that may
* contain the requested entries.
* @param message the additional error information
* @param resultCode result code
* @param referrals array of LDAP URLs identifying other LDAP servers that
* may contain the requested entries
*/
public LDAPReferralException( String message,
int resultCode,
String referrals[] ) {
super(message, resultCode, (String)null);
_referrals = referrals;
}
/**
* Constructs an exception with a result code, a specified
* string of additional information, a string containing
* information passed back from the server, and a possible root
* exception.
* <P>
*
* After you construct the <CODE>LDAPException</CODE> object,
* the result code and messages will be accessible through the
* following ways:
* <P>
* <UL>
* <LI>This string of additional information appears if you
* call the <CODE>toString()</CODE> method. <P>
* <LI>The result code that you set is accessible through the
* <CODE>getLDAPResultCode()</CODE> method. <P>
* <LI>The string of server error information that you set
* is accessible through the <CODE>getLDAPErrorMessage</CODE>
* method. <P>
* </UL>
* <P>
*
* This form is used for higher-level LDAP operational errors.
* @param message the additional error information
* @param resultCode the result code returned
* @param serverErrorMessage error message specifying additional information
* returned from the server
* @param rootException An exception which caused the failure, if any
* @see org.ietf.ldap.LDAPException#toString()
* @see org.ietf.ldap.LDAPException#getResultCode()
* @see org.ietf.ldap.LDAPException#getLDAPErrorMessage()
* @see org.ietf.ldap.LDAPException#getMatchedDN()
*/
public LDAPReferralException( String message,
int resultCode,
String serverErrorMessage,
Throwable rootException ) {
super( message, resultCode, serverErrorMessage, rootException );
}
/**
* Gets the list of referrals (LDAP URLs to other servers) returned by the LDAP server.
* You can use this list to find the LDAP server that can fulfill your request.
*
* If you have set up your search constraints (or the <CODE>LDAPConnection</CODE> object)
* to follow referrals automatically, any operation that results in a referral will use
* this list to create new connections to the LDAP servers in this list.
*
* @return list of LDAP URLs to other LDAP servers.
*/
public String[] getReferrals() {
if ( getLDAPErrorMessage() == null ) {
return (_referrals != null) ? _referrals : new String[0];
} else {
return extractReferrals( getLDAPErrorMessage() );
}
}
/**
* Gets the referral URL that could not be followed. If multiple URLs
* are in the list, and none could be followed, the method returns one
* of them.
*
* @return the referral URL that could not be followed
*/
public String getFailedReferral() {
String[] urls = getReferrals();
return (urls.length > 0) ? urls[0] : "";
}
/**
* Sets the referral URL that could not be followed
*
* @param referral the referral URL that could not be followed
*/
public void setFailedReferral( String referral ) {
_referrals = new String[] { referral };
}
/**
* Extract referral string from the error message. The
* error string is based on "Referrals Within the
* LDAPConnection Protocol".
* @param error string
*/
private String[] extractReferrals(String error) {
if (error == null)
return null;
StringTokenizer st = new StringTokenizer(error, "\n");
Vector v = new Vector();
boolean referrals = false;
while (st.hasMoreTokens()) {
String token = st.nextToken();
if (referrals) {
v.addElement(token);
} else {
if (token.startsWith("Referral:"))
referrals = true;
}
}
if (v.size() == 0)
return null;
String res[] = new String[v.size()];
for (int i = 0; i < v.size(); i++) {
res[i] = (String)v.elementAt(i);
}
return res;
}
/**
* Gets the string representation of the referral exception,
* which includes the result code, the message sent back
* from the LDAP server and the list of referrals.
*
* @return string representation of exception.
* @see org.ietf.ldap.LDAPException#resultCodeToString(int)
*/
public String toString() {
String str = super.toString();
for (int i=0; i < _referrals.length; i++) {
str += "\n" + _referrals[i];
}
return str;
}
}

View File

@@ -0,0 +1,28 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
/**
* Common base interface for referral handlers
*/
public interface LDAPReferralHandler {
}

View File

@@ -0,0 +1,123 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
import java.io.*;
/**
* This class represents a locale-specific resource for a property file.
* It retrieves the property file for the given base name including the
* absolute path name and locale. The property file has to be located in the
* CLASSPATH and the property file's suffix is .props.
* <p>
* If the specified locale is en and us and the base name of the file is
* netscape/ldap/errors/ErrorCodes, then the class loader will search for
* the file in the following order:
* <pre>
*
* ErrorCodes_en_us.properties
* ErrorCodes_en.properties
* ErrorCodes.properties
*
* </pre>
* @see java.util.Locale
*/
class LDAPResourceBundle implements java.io.Serializable {
static final long serialVersionUID = -5903986665461157980L;
private static final boolean _debug = false;
private static final String _suffix = ".properties";
private static final String _locale_separator = "_";
/**
* Return the property resource bundle according to the base name of the
* property file and the locale. The class loader will find the closest match
* with the given locale.
* @return the property resource bundle.
* @exception IOException Gets thrown when failed to open the resource
* bundle file.
*/
static PropertyResourceBundle getBundle( String baseName )
throws IOException {
return getBundle( baseName, Locale.getDefault() );
}
/**
* Return the property resource bundle according to the base name of the
* property file and the locale. The class loader will find the closest match
* with the given locale.
* @param baseName the base name of the property file. The base name contains
* no locale context and no . suffix.
* @param l the locale
* @return the property resource bundle.
* @exception IOException Gets thrown when failed to create a property
* resource
*/
static PropertyResourceBundle getBundle( String baseName, Locale l )
throws IOException {
String localeStr = _locale_separator + l.toString();
InputStream fin = null;
while ( true ) {
if ( (fin = getStream(baseName, localeStr)) != null ) {
PropertyResourceBundle p = new PropertyResourceBundle( fin );
return p;
} else {
int index = localeStr.lastIndexOf( _locale_separator );
if ( index == -1 ) {
printDebug( "File " + baseName + localeStr + _suffix +
" not found" );
return null;
} else {
localeStr = localeStr.substring( 0, index );
}
}
}
}
/**
* Constructs the whole absolute path name of a property file and retrieves
* an input stream on the file.
* @param baseName the base name of the property file. The base name contains
* no locale context and no . suffix.
* @param the locale string to insert into the file name
* @return the input stream of the property file.
*/
private static InputStream getStream( String baseName, String locale ) {
String fStr = baseName + locale + _suffix;
return ClassLoader.getSystemResourceAsStream( fStr );
}
/**
* Prints debug messages if the debug mode is on.
* @param str the message that is printed
*/
private static void printDebug(String str) {
if ( _debug ) {
System.out.println( str );
}
}
}

View File

@@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import org.ietf.ldap.client.opers.JDAPProtocolOp;
import org.ietf.ldap.client.opers.JDAPResult;
/**
* Represents the response to a particular LDAP operation.
*
* @version 1.0
*/
public class LDAPResponse extends LDAPMessage {
static final long serialVersionUID = 5822205242593427418L;
/**
* Constructor
*
* @param msgid message identifier
* @param rsp operation response
* @param controls array of controls or null
*/
LDAPResponse(int msgid, JDAPProtocolOp rsp, LDAPControl controls[]) {
super(msgid, rsp, controls);
}
/**
* Returns any error message in the response.
*
* @return the error message of the last error (or <CODE>null</CODE>
* if no message was set).
*/
public String getErrorMessage() {
JDAPResult result = (JDAPResult) getProtocolOp();
return result.getErrorMessage();
}
/**
* Returns the partially matched DN field, if any, in a server response.
*
* @return the maximal subset of a DN to match,
* or <CODE>null</CODE>.
*/
public String getMatchedDN() {
JDAPResult result = (JDAPResult) getProtocolOp();
return result.getMatchedDN();
}
/**
* Returns all referrals, if any, in a server response.
*
* @return a list of referrals or <CODE>null</CODE>.
*/
public String[] getReferrals() {
JDAPResult result = (JDAPResult) getProtocolOp();
return result.getReferrals();
}
/**
* Returns the result code in a server response.
*
* @return the result code.
*/
public int getResultCode() {
JDAPResult result = (JDAPResult) getProtocolOp();
return result.getResultCode();
}
}

View File

@@ -0,0 +1,56 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
/*
* This object represents the value of the LDAPConnection.m_responseControlTable hashtable.
* It stores the response controls and its corresponding LDAPConnection and
* the message ID for its corresponding LDAPMessage.
*/
class LDAPResponseControl implements java.io.Serializable {
static final long serialVersionUID = 389472019686058593L;
private LDAPConnection m_connection;
private int m_messageID;
private LDAPControl[] m_controls;
public LDAPResponseControl(LDAPConnection conn, int msgID,
LDAPControl[] controls) {
m_connection = conn;
m_messageID = msgID;
m_controls = new LDAPControl[controls.length];
for (int i=0; i<controls.length; i++)
m_controls[i] = controls[i];
}
public int getMsgID() {
return m_messageID;
}
public LDAPControl[] getControls() {
return m_controls;
}
public LDAPConnection getConnection() {
return m_connection;
}
}

View File

@@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.io.Serializable;
import java.util.Vector;
/**
* Represents the message queue associated with a particular LDAP
* operation or operations.
*
*/
public class LDAPResponseQueue extends LDAPMessageQueueImpl {
static final long serialVersionUID = 901897097111294329L;
/**
* Constructor
*
* @param asynchOp a boolean flag that is true if the object is used for
* asynchronous LDAP operations
* @see org.ietf.ldap.LDAPAsynchronousConnection
*/
LDAPResponseQueue( boolean asynchOp ) {
super( asynchOp );
}
}

View File

@@ -0,0 +1,314 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.io.*;
import java.net.*;
/**
* Creates an SSL socket connection to an LDAP Server. This class
* implements the <CODE>LDAPSSLSocketFactoryExt</CODE> interface.
* <P>
*
* To construct an object of this class, you need to specify the
* name of a class that implements the <CODE>javax.net.ssl.SSLSocket</CODE>
* interface. If you do not specify a class name, the class
* <CODE>netscape.net.SSLSocket</CODE> is used by default. This
* class is included with Netscape Communicator 4.05 and up.
* <P>
*
* If you are using a Java VM that provides certificate database
* management (such as Netscape Communicator), you can authenticate
* your client to a secure LDAP server by using certificates.
* <P>
*
* @version 1.0
* @see LDAPSSLSocketFactoryExt
* @see LDAPConnection#LDAPConnection(org.ietf.ldap.LDAPSocketFactory)
*/
public class LDAPSSLSocketFactory
implements LDAPSSLSocketFactoryExt, Serializable {
static final long serialVersionUID = -3331456736649381427L;
/**
* Indicates if client authentication is on.
*/
private boolean _clientAuth = false;
/**
* Name of class implementing SSLSocket.
*/
private String _packageName = "netscape.net.SSLSocket";
/**
* The cipher suites
*/
private Object _cipherSuites = null;
/**
* Constructs an <CODE>LDAPSSLSocketFactory</CODE> object using
* the default SSL socket implementation,
* <CODE>netscape.net.SSLSocket</CODE>. (This class is provided
* with Netscape Communicator 4.05 and higher.)
*/
public LDAPSSLSocketFactory() {
}
/**
* Constructs an <CODE>LDAPSSLSocketFactory</CODE> object using
* the default SSL socket implementation,
* <CODE>netscape.net.SSLSocket</CODE>. (This class is provided
* with Netscape Communicator 4.05 and up.)
* @param clientAuth <CODE>true</CODE> if certificate-based client
* authentication is desired. By default, client authentication is
* not used.
*/
public LDAPSSLSocketFactory(boolean clientAuth) {
_clientAuth = clientAuth;
}
/**
* Constructs an <CODE>LDAPSSLSocketFactory</CODE> object using
* the specified class. The class must implement the interface
* <CODE>javax.net.ssl.SSLSocket</CODE>.
* @param className the name of a class implementing
* the <CODE>javax.net.ssl.SSLSocket</CODE> interface.
* Pass <code>null</code> for this parameter to use the
* default SSL socket implementation,
* <CODE>netscape.net.SSLSocket</CODE>, which is included with
* Netscape Communicator 4.05 and higher.
*/
public LDAPSSLSocketFactory(String className) {
_packageName = new String(className);
}
/**
* Constructs an <CODE>LDAPSSLSocketFactory</CODE> object using
* the specified class. The class must implement the interface
* <CODE>javax.net.ssl.SSLSocket</CODE>.
* @param className the name of a class implementing
* the <CODE>javax.net.ssl.SSLSocket</CODE> interface.
* Pass <code>null</code> for this parameter to use the
* default SSL socket implementation,
* <CODE>netscape.net.SSLSocket</CODE>, which is included with
* Netscape Communicator 4.05 and higher.
* @param clientAuth <CODE>true</CODE> if certificate-based client
* authentication is desired. By default, client authentication is
* not used.
*/
public LDAPSSLSocketFactory(String className, boolean clientAuth) {
_packageName = new String(className);
_clientAuth = clientAuth;
}
/**
* The constructor with the specified package for security and the specified
* cipher suites.
* @param className the name of a class implementing the interface
* <CODE>javax.net.ssl.SSLSocket</CODE>.
* Pass <code>null</code> for this parameter to use the
* default SSL socket implementation,
* <CODE>netscape.net.SSLSocket</CODE>, which is included with
* Netscape Communicator 4.05 and higher.
* @param cipherSuites the cipher suites to use for SSL connections
*/
public LDAPSSLSocketFactory(String className, Object cipherSuites) {
_packageName = new String(className);
_cipherSuites = cipherSuites;
}
/**
* The constructor with the specified package for security and the specified
* cipher suites.
* @param className the name of a class implementing the interface
* <CODE>javax.net.ssl.SSLSocket</CODE>.
* Pass <code>null</code> for this parameter to use the
* default SSL socket implementation,
* <CODE>netscape.net.SSLSocket</CODE>, which is included with
* Netscape Communicator 4.05 and higher.
* @param cipherSuites the cipher suites to use for SSL connections
* @param clientAuth <CODE>true</CODE> if certificate-based client
* authentication is desired. By default, client authentication is
* not used.
*/
public LDAPSSLSocketFactory(String className, Object cipherSuites,
boolean clientAuth) {
_packageName = new String(className);
_cipherSuites = cipherSuites;
_clientAuth = clientAuth;
}
/**
* Enables certificate-based client authentication for an
* application. The application must be running in a Java VM
* that provides transparent certificate database management
* (for example, Netscape Communicator's Java VM).
* Call this method before you call <CODE>createSocket</CODE>.
* @see org.ietf.ldap.LDAPSSLSocketFactory#isClientAuth
* @see org.ietf.ldap.LDAPSSLSocketFactory#createSocket
* Note: enableClientAuth() is deprecated. This method is replaced
* by any one of the following constructors:
* <p>
* <CODE>LDAPSSLSocketFactory(boolean)</CODE>
* <CODE>LDAPSSLSocketFactory(java.lang.String, boolean)</CODE>
* <CODE>LDAPSSLSocketFactory(java.lang.String, java.lang.Object, boolean)</CODE>
*/
public void enableClientAuth() {
_clientAuth = true;
}
/**
* Enables client authentication for an application that uses
* an external (file-based) certificate database.
* <B>This method is currently not implemented.</B>
* Call this method before you call <CODE>createSocket</CODE>.
* @param certdb the pathname for the certificate database
* @param keydb the pathname for the private key database
* @param keypwd the password for the private key database
* @param certnickname the alias for the certificate
* @param keynickname the alias for the key
* @see org.ietf.ldap.LDAPSSLSocketFactory#isClientAuth
* @see org.ietf.ldap.LDAPSSLSocketFactory#createSocket
* @exception LDAPException Since this method is not yet implemented,
* calling this method throws an exception.
* Note: <CODE>enableClientAuth(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)</CODE> is deprecated.
* This method is replaced by any one of the following constructors:
* <p>
* <CODE>LDAPSSLSocketFactory(boolean)</CODE>
* <CODE>LDAPSSLSocketFactory(java.lang.String, boolean)</CODE>
* <CODE>LDAPSSLSocketFactory(java.lang.String, java.lang.Object, boolean)</CODE>
*/
public void enableClientAuth(String certdb, String keydb, String keypwd,
String certnickname, String keynickname) throws LDAPException {
throw new LDAPException("Client auth not supported now");
}
/**
* Returns <code>true</code> if client authentication is enabled.
* @see org.ietf.ldap.LDAPSSLSocketFactory
*/
public boolean isClientAuth() {
return _clientAuth;
}
/**
* Returns the name of the class that implements SSL sockets for this factory.
*
* @return the name of the class that implements SSL sockets for this factory.
*/
public String getSSLSocketImpl() {
return _packageName;
}
/**
* Returns the suite of ciphers used for SSL connections made through
* sockets created by this factory.
*
* @return the suite of ciphers used.
*/
public Object getCipherSuites() {
return _cipherSuites;
}
/**
* Returns a socket to the LDAP server with the specified
* host name and port number.
* @param host the host to connect to
* @param port the port number
* @return the socket to the host name and port number.
* @exception LDAPException A socket to the specified host and port
* could not be created.
* @see org.ietf.ldap.LDAPSSLSocketFactory
*/
public Socket createSocket(String host, int port)
throws LDAPException {
Socket s = null;
if (_clientAuth) {
try {
/* Check if running in Communicator; if so, enable client
auth */
String[] types = { "java.lang.String" };
java.lang.reflect.Method m =
DynamicInvoker.getMethod(
"netscape.security.PrivilegeManager",
"enablePrivilege",
types );
if (m != null) {
Object[] args = new Object[1];
args[0] = new String("ClientAuth");
m.invoke( null, args);
}
} catch (Exception e) {
String msg = "LDAPSSLSocketFactory.createSocket: invoking " +
"enablePrivilege: " + e.toString();
throw new LDAPException(msg, LDAPException.PARAM_ERROR);
}
}
try {
String cipherClassName = null;
if (_cipherSuites != null)
cipherClassName = _cipherSuites.getClass().getName();
/* Instantiate the SSLSocketFactory implementation, and
find the right constructor */
Class c = Class.forName(_packageName);
java.lang.reflect.Constructor[] m = c.getConstructors();
for (int i = 0; i < m.length; i++) {
/* Check if the signature is right: String, int */
Class[] params = m[i].getParameterTypes();
if ( (_cipherSuites == null) && (params.length == 2) &&
(params[0].getName().equals("java.lang.String")) &&
(params[1].getName().equals("int")) ) {
Object[] args = new Object[2];
args[0] = host;
args[1] = new Integer(port);
s = (Socket)(m[i].newInstance(args));
return s;
} else if ( (_cipherSuites != null) && (params.length == 3) &&
(params[0].getName().equals("java.lang.String")) &&
(params[1].getName().equals("int")) &&
(params[2].getName().equals(cipherClassName)) ) {
Object[] args = new Object[3];
args[0] = host;
args[1] = new Integer(port);
args[2] = _cipherSuites;
s = (Socket)(m[i].newInstance(args));
return s;
}
}
throw new LDAPException("No appropriate constructor in " +
_packageName,
LDAPException.PARAM_ERROR);
} catch (ClassNotFoundException e) {
throw new LDAPException("Class " + _packageName + " not found",
LDAPException.PARAM_ERROR);
} catch (Exception e) {
throw new LDAPException("Failed to create SSL socket",
LDAPException.CONNECT_ERROR);
}
}
}

View File

@@ -0,0 +1,50 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
/**
* Represents an SSL socket connection that you can use to connect to an
* LDAP server. This interface extends the base interface LDAPSocketFactory
* and provides SSL-specific methods.
* <P>
*
* @version 1.0
* @see LDAPSocketFactory
* @see LDAPConnection#LDAPConnection(org.ietf.ldap.LDAPSocketFactory)
*/
public interface LDAPSSLSocketFactoryExt extends LDAPSocketFactory {
/**
* Returns the suite of ciphers used for SSL connections. These connections
* are made through sockets created by the LDAPSSLSocketFactory.
*
* @return the suite of ciphers used.
*/
public Object getCipherSuites();
/**
* Returns <code>true</code> if client authentication is enabled.
* @see org.ietf.ldap.LDAPSSLSocketFactory#enableClientAuth
*/
public boolean isClientAuth();
}

View File

@@ -0,0 +1,355 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.io.*;
import java.net.*;
import java.util.Hashtable;
/**
* Creates an SSL socket connection to an LDAP Server. This class is provided
* by the package in which the SSL socket does not extend Socket object.
* The class internally provides a wrapper to convert the SSL socket extending
* the Object class to the one extending the Socket class.
* This factory class implements the <CODE>LDAPSocketFactory</CODE> interface.
* <P>
*
* To use this class, pass the instance of this factory object to the
* <CODE>LDAPConnection</CODE> constructor.
*
* @version 1.0
* @see LDAPSocketFactory
* @see LDAPConnection#LDAPConnection(org.ietf.ldap.LDAPSocketFactory)
*/
public class LDAPSSLSocketWrapFactory
implements LDAPSSLSocketFactoryExt, java.io.Serializable {
static final long serialVersionUID = -4171548771815037740L;
/**
* The constructor with the specified package for security
* @param className the name of a class which has an implementation
* of the SSL Socket extending Object class
*/
public LDAPSSLSocketWrapFactory(String className) {
_packageName = new String(className);
}
/**
* The constructor with the specified package for security and the
* specified cipher suites.
* @param className the name of a class which has an implementation
* of the SSL Socket extending Object class
* @param cipherSuites the cipher suites
*/
public LDAPSSLSocketWrapFactory(String className, Object cipherSuites) {
_packageName = new String(className);
_cipherSuites = cipherSuites;
}
/**
* Returns socket to the specified host name and port number.
* @param host the host to connect to
* @param port the port number
* @return the socket to the host name and port number as passed in.
* @exception LDAPException A socket to the specified host and port
* could not be created.
*/
public Socket createSocket(String host, int port) throws LDAPException {
LDAPSSLSocket s = null;
try {
if (_cipherSuites == null)
s = new LDAPSSLSocket(host, port, _packageName);
else
s = new LDAPSSLSocket(host, port, _packageName,
_cipherSuites);
return s;
} catch (Exception e) {
System.err.println("Exception: "+e.toString());
throw new LDAPException("Failed to create SSL socket",
LDAPException.CONNECT_ERROR);
}
}
/**
* Returns <code>true</code> if client authentication is to be used.
* @return <code>true</code> if client authentication is enabled;
* <code>false</code>if client authentication is disabled.
*/
public boolean isClientAuth() {
return _clientAuth;
}
/**
* <B>(Not implemented yet)</B> <BR>
* Enables client authentication for an application running in
* a java VM which provides transparent certificate database management.
* Calling this method has no effect after createSocket() has been
* called.
* @exception LDAPException Since this method is not yet implemented,
* calling this method throws an exception.
*/
public void enableClientAuth() throws LDAPException {
throw new LDAPException("Client Authentication is not implemented yet.");
}
/**
* Returns the name of the class that implements SSL sockets for this factory.
*
* @return the name of the class that implements SSL sockets for this factory.
*/
public String getSSLSocketImpl() {
return _packageName;
}
/**
* Returns the suite of ciphers used for SSL connections made through
* sockets created by this factory.
*
* @return the suite of ciphers used.
*/
public Object getCipherSuites() {
return _cipherSuites;
}
/**
* Indicates if client authentication is on.
*/
private boolean _clientAuth = false;
/**
* Name of class implementing SSLSocket.
*/
private String _packageName = null;
/**
* The cipher suites
*/
private Object _cipherSuites = null;
}
// LDAPSSLSocket class wraps the implementation of the SSL socket
class LDAPSSLSocket extends Socket {
public LDAPSSLSocket(String host, int port, String packageName)
throws LDAPException {
super();
_packageName = packageName;
try {
// instantiate the SSLSocketFactory implementation, and
// find the right constructor
Class c = Class.forName(_packageName);
java.lang.reflect.Constructor[] m = c.getConstructors();
for (int i = 0; i < m.length; i++) {
/* Check if the signature is right: String, int */
Class[] params = m[i].getParameterTypes();
if ((params.length == 2) &&
(params[0].getName().equals("java.lang.String")) &&
(params[1].getName().equals("int"))) {
Object[] args = new Object[2];
args[0] = host;
args[1] = new Integer(port);
_socket = (Object)(m[i].newInstance(args));
return;
}
}
throw new LDAPException("No appropriate constructor in " +
_packageName, LDAPException.PARAM_ERROR);
} catch (ClassNotFoundException e) {
throw new LDAPException("Class " + _packageName + " not found",
LDAPException.OTHER);
} catch (Exception e) {
throw new LDAPException("Failed to create SSL socket",
LDAPException.CONNECT_ERROR);
}
}
public LDAPSSLSocket(String host, int port, String packageName,
Object cipherSuites) throws LDAPException {
super();
_packageName = packageName;
String cipherClassName = null;
if (cipherSuites != null)
cipherClassName = cipherSuites.getClass().getName();
try {
// instantiate the SSLSocketFactory implementation, and
// find the right constructor
Class c = Class.forName(_packageName);
java.lang.reflect.Constructor[] m = c.getConstructors();
for (int i = 0; i < m.length; i++) {
/* Check if the signature is right: String, int */
Class[] params = m[i].getParameterTypes();
if (cipherSuites == null)
throw new LDAPException("Cipher Suites is required");
if ((params.length == 3) &&
(params[0].getName().equals("java.lang.String")) &&
(params[1].getName().equals("int")) &&
(params[2].getName().equals(cipherClassName))) {
Object[] args = new Object[3];
args[0] = host;
args[1] = new Integer(port);
args[2] = cipherSuites;
_socket = (Object)(m[i].newInstance(args));
return;
}
}
throw new LDAPException("No appropriate constructor in " +
_packageName, LDAPException.PARAM_ERROR);
} catch (ClassNotFoundException e) {
throw new LDAPException("Class " + _packageName + " not found",
LDAPException.OTHER);
} catch (Exception e) {
throw new LDAPException("Failed to create SSL socket",
LDAPException.CONNECT_ERROR);
}
}
public InputStream getInputStream() {
try {
Object obj = invokeMethod(_socket, "getInputStream", null);
return (InputStream)obj;
} catch (LDAPException e) {
printDebug(e.toString());
}
return null;
}
public OutputStream getOutputStream() {
try {
Object obj = invokeMethod(_socket, "getOutputStream", null);
return (OutputStream)obj;
} catch (LDAPException e) {
printDebug(e.toString());
}
return null;
}
public void close() throws IOException {
try {
invokeMethod(_socket, "close", null);
} catch (LDAPException e) {
printDebug(e.toString());
}
}
public void close(boolean wait) throws IOException {
try {
Object[] args = new Object[1];
args[0] = new Boolean(wait);
invokeMethod(_socket, "close", args);
} catch (LDAPException e) {
printDebug(e.toString());
}
}
public InetAddress getInetAddress() {
try {
Object obj = invokeMethod(_socket, "getInetAddress", null);
return (InetAddress)obj;
} catch (LDAPException e) {
printDebug(e.toString());
}
return null;
}
public int getLocalPort() {
try {
Object obj = invokeMethod(_socket, "getLocalPort", null);
return ((Integer)obj).intValue();
} catch (LDAPException e) {
printDebug(e.toString());
}
return -1;
}
public int getPort() {
try {
Object obj = invokeMethod(_socket, "getPort", null);
return ((Integer)obj).intValue();
} catch (LDAPException e) {
printDebug(e.toString());
}
return -1;
}
private Object invokeMethod(Object obj, String name, Object[] args) throws
LDAPException {
try {
java.lang.reflect.Method m = getMethod(name);
if (m != null) {
return (m.invoke(obj, args));
}
} catch (Exception e) {
throw new LDAPException("Invoking "+name+": "+
e.toString(), LDAPException.PARAM_ERROR);
}
return null;
}
private java.lang.reflect.Method getMethod(String name) throws
LDAPException {
try {
java.lang.reflect.Method method = null;
if ((method = (java.lang.reflect.Method)(_methodLookup.get(name)))
!= null)
return method;
Class c = Class.forName(_packageName);
java.lang.reflect.Method[] m = c.getMethods();
for (int i = 0; i < m.length; i++ ) {
if (m[i].getName().equals(name)) {
_methodLookup.put(name, m[i]);
return m[i];
}
}
throw new LDAPException("Method " + name + " not found in " +
_packageName);
} catch (ClassNotFoundException e) {
throw new LDAPException("Class "+ _packageName + " not found");
}
}
private void printDebug(String msg) {
if (_debug) {
System.out.println(msg);
}
}
private final boolean _debug = true;
private Object _socket;
private Hashtable _methodLookup = new Hashtable();
private String _packageName = null;
}

View File

@@ -0,0 +1,447 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
import org.ietf.ldap.client.*;
import org.ietf.ldap.client.opers.*;
import org.ietf.ldap.ber.stream.*;
import org.ietf.ldap.util.*;
import java.io.*;
import java.net.*;
import javax.security.auth.callback.CallbackHandler;
import javax.security.sasl.*;
/**
* Authenticates to a server using SASL
*/
public class LDAPSaslBind implements LDAPBindHandler, Serializable {
static final long serialVersionUID = -7615315715163655443L;
/**
* Construct an object which can authenticate to an LDAP server
* using the specified name and a specified SASL mechanism.
*
* @param dn if non-null and non-empty, specifies that the connection and
* all operations through it should authenticate with dn as the
* distinguished name
* @param mechanisms array of mechanism names, e.g. { "GSSAPI", "SKEY" }
* @param props optional additional properties of the desired
* authentication mechanism, e.g. minimum security level
* @param cbh a class which may be called by the SASL framework to
* obtain additional required information
*/
public LDAPSaslBind( String dn,
String[] mechanisms,
Map props,
CallbackHandler cbh ) {
_dn = dn;
_mechanisms = mechanisms;
_props = props;
_cbh = cbh;
}
/**
* Authenticates to the LDAP server (that the object is currently
* connected to) using the parameters that were provided to the
* constructor. If the requested SASL mechanism is not
* available, an exception is thrown. If the object has been
* disconnected from an LDAP server, this method attempts to reconnect
* to the server. If the object had already authenticated, the old
* authentication is discarded.
*
* @param ldc an active connection to a server, which will have
* the new authentication state on return from the method
* @exception LDAPException Failed to authenticate to the LDAP server.
*/
public void bind( LDAPConnection ldc ) throws LDAPException {
if ( _props == null ) {
_props = new HashMap();
}
String packageNames = (String)_props.get( CLIENTPKGS );
if ( packageNames == null ) {
packageNames = System.getProperty( CLIENTPKGS );
}
if ( packageNames == null ) {
packageNames = ldc.DEFAULT_SASL_PACKAGE;
}
StringTokenizer st = new StringTokenizer( packageNames, "|" );
while( st.hasMoreTokens() ) {
String packageName = st.nextToken();
try {
_saslClient = getClient( ldc, packageName );
if ( _saslClient != null ) {
break;
}
} catch ( LDAPException e ) {
if ( !st.hasMoreTokens() ) {
throw e;
}
}
}
if ( _saslClient != null ) {
bind( ldc, true );
return;
} else {
ldc.printDebug( "LDAPSaslBind.bind: getClient " +
"returned null" );
}
}
/**
* Authenticates to the LDAP server (that the object is currently
* connected to) using the parameters that were provided to the
* constructor. If the requested SASL mechanism is not
* available, an exception is thrown. If the object has been
* disconnected from an LDAP server, this method attempts to reconnect
* to the server. If the object had already authenticated, the old
* authentication is discarded.
*
* @param ldapurls urls which may be selected to connect and bind to
* @param ldc an active connection to a server, which will have
* the new authentication state on return from the method
* @exception LDAPReferralException Failed to authenticate to the LDAP
* server
*/
public void bind( String[] ldapurls,
LDAPConnection conn ) throws LDAPReferralException {
try {
// ??? What to do with the URLs?
bind( conn );
} catch ( LDAPReferralException ex ) {
throw ex;
} catch ( LDAPException ex ) {
// ???
throw new LDAPReferralException( ex.getMessage(),
ex.getResultCode(),
ex.getLDAPErrorMessage() );
}
}
/**
* Get a SaslClient object from the Sasl framework
*
* @param ldc contains the host name
* @param packageName package containing a ClientFactory
* @return a SaslClient supporting one of the mechanisms
* of the member variable _mechanisms.
* @exception LDAPException on error producing a client
*/
private Object getClient( LDAPConnection ldc, String packageName )
throws LDAPException {
try {
Object[] args = new Object[6];
args[0] = _mechanisms;
args[1] = _dn;
args[2] = "ldap";
args[3] = ldc.getHost();
args[4] = _props;
args[5] = _cbh;
String[] argNames = new String[6];
argNames[0] = "[Ljava.lang.String;";
argNames[1] = "java.lang.String";
argNames[2] = "java.lang.String";
argNames[3] = "java.lang.String";
argNames[4] = "java.util.Map";
argNames[5] = CALLBACK_HANDLER;
// Get a mechanism driver
return DynamicInvoker.invokeMethod( null,
"javax.security.sasl.Sasl",
"createSaslClient",
args, argNames );
} catch ( Exception e ) {
ldc.printDebug( "LDAPSaslBind.getClient: " +
packageName+".Sasl.createSaslClient: " +
e );
throw new LDAPException( e.toString(), LDAPException.OTHER );
}
}
void bind( LDAPConnection ldc, boolean rebind )
throws LDAPException {
if ( (ldc.isConnected() && rebind) ||
!ldc.isConnected() ) {
try {
String className = _saslClient.getClass().getName();
ldc.printDebug( "LDAPSaslBind.bind: calling " +
className+".hasInitialResponse" );
// Get initial response if any
byte[] outVals = null;
if ( hasInitialResponse() ) {
outVals = evaluateChallenge( new byte[0] );
}
String mechanismName = getMechanismName();
ldc.printDebug( "LDAPSaslBind.bind: mechanism " +
"name is " +
mechanismName );
boolean isExternal = isExternalMechanism( mechanismName );
ldc.printDebug( "LDAPSaslBind.bind: calling " +
"saslBind" );
JDAPBindResponse response =
saslBind( ldc, mechanismName, outVals );
int resultCode = response.getResultCode();
while ( !checkForSASLBindCompletion( ldc, resultCode ) ) {
if ( isExternal ) {
continue;
}
byte[] b = response.getCredentials();
if ( b == null ) {
b = new byte[0];
}
outVals = evaluateChallenge( b );
ldc.printDebug( "SaslClient.evaluateChallenge returned [" +
((outVals != null) ?
new String( outVals ) : "null") +
"] for [" + new String( b ) + "]" );
if ( resultCode == LDAPException.SUCCESS ) {
// we're done; don't expect to send another BIND
if ( outVals != null ) {
throw new LDAPException(
"Protocol error: attempting to send " +
"response after completion" );
}
break;
}
response = saslBind( ldc, mechanismName, outVals );
resultCode = response.getResultCode();
}
// Make sure authentication REALLY is complete
if ( !isComplete() ) {
// Authentication session hijacked!
throw new LDAPException( "The server indicates that " +
"authentication is successful" +
", but the SASL driver " +
"indicates that authentication" +
" is not yet done.",
LDAPException.OTHER );
} else if ( resultCode == LDAPException.SUCCESS ) {
// Has a security layer been negotiated?
String qop = (String)getNegotiatedProperty( QOP );
if ( (qop != null) &&
(qop.equalsIgnoreCase("auth-int") ||
qop.equalsIgnoreCase("auth-conf")) ) {
// Use SaslClient.wrap() and SaslClient.unwrap() for
// future communication with server
ldc.setInputStream(
new SecureInputStream( ldc.getInputStream(),
_saslClient ) );
ldc.setOutputStream(
new SecureOutputStream( ldc.getOutputStream(),
_saslClient ) );
}
ldc.markConnAsBound();
}
} catch (LDAPException e) {
throw e;
} catch (Exception e) {
throw new LDAPException(e.toString(), LDAPException.OTHER);
}
}
}
boolean isExternalMechanism( String name ) {
return name.equalsIgnoreCase( LDAPConnection.EXTERNAL_MECHANISM );
}
// Wrapper functions for dynamically invoking methods of SaslClient
private boolean checkForSASLBindCompletion( LDAPConnection ldc,
int resultCode )
throws LDAPException {
ldc.printDebug( "LDAPSaslBind.bind: saslBind " +
"returned " + resultCode );
if ( isComplete() ) {
if ( (resultCode == LDAPException.SUCCESS) ||
(resultCode == LDAPException.SASL_BIND_IN_PROGRESS) ) {
return true;
} else {
throw new LDAPException( "Authentication failed", resultCode );
}
} else {
return false;
}
}
private boolean hasInitialResponse()
throws LDAPException {
if ( !_useReflection ) {
return ((SaslClient)_saslClient).hasInitialResponse();
} else {
return ((Boolean)DynamicInvoker.invokeMethod(
_saslClient,
_saslClient.getClass().getName(),
"hasInitialResponse",
null,
null)).booleanValue();
}
}
private String getMechanismName()
throws LDAPException {
if ( !_useReflection ) {
return ((SaslClient)_saslClient).getMechanismName();
} else {
return (String)DynamicInvoker.invokeMethod(
_saslClient,
_saslClient.getClass().getName(),
"getMechanismName",
null,
null );
}
}
private boolean isComplete()
throws LDAPException {
if ( !_useReflection ) {
return ((SaslClient)_saslClient).isComplete();
} else {
return ((Boolean)DynamicInvoker.invokeMethod(
_saslClient,
_saslClient.getClass().getName(),
"isComplete",
null,
null)).booleanValue();
}
}
private byte[] evaluateChallenge( byte[] b )
throws LDAPException {
try {
if ( !_useReflection ) {
return ((SaslClient)_saslClient).evaluateChallenge( b );
} else {
Object[] args = { b };
String[] argNames = { "[B" }; // class name for byte array
return (byte[])DynamicInvoker.invokeMethod(
_saslClient,
_saslClient.getClass().getName(),
"evaluateChallenge",
args,
argNames );
}
} catch ( Exception e ) {
throw new LDAPException( "",
LDAPException.PARAM_ERROR,
e );
}
}
private Object getNegotiatedProperty( String propName )
throws LDAPException {
try {
if ( !_useReflection ) {
return ((SaslClient)_saslClient).getNegotiatedProperty(
propName );
} else {
Object[] args = { propName };
String[] argNames = { "String" };
return DynamicInvoker.invokeMethod(
_saslClient,
_saslClient.getClass().getName(),
"getNegotiatedProperty",
args,
argNames );
}
} catch ( Exception e ) {
throw new LDAPException( "",
LDAPException.PARAM_ERROR,
e );
}
}
private JDAPBindResponse saslBind( LDAPConnection ldc,
String mechanismName,
byte[] credentials )
throws LDAPException {
LDAPResponseQueue myListener = ldc.getResponseListener();
try {
ldc.sendRequest( new JDAPBindRequest( 3,
_dn,
mechanismName,
credentials ),
myListener, ldc.getConstraints() );
LDAPMessage response = myListener.getResponse();
JDAPProtocolOp protocolOp = response.getProtocolOp();
if ( protocolOp instanceof JDAPBindResponse ) {
return (JDAPBindResponse)protocolOp;
} else {
throw new LDAPException( "Unknown response from the " +
"server during SASL bind",
LDAPException.OTHER );
}
} finally {
ldc.releaseResponseListener( myListener );
}
}
private static final String CALLBACK_HANDLER =
"javax.security.auth.callback.CallbackHandler";
static final String CLIENTPKGS =
"javax.security.sasl.client.pkgs";
private static final String QOP = "javax.security.sasl.qop";
private static final String REFLECTION_PROP =
"org.ietf.ldap.sasl.reflect";
private String _dn;
private String[] _mechanisms;
private Map _props = null;
private CallbackHandler _cbh;
private Object _saslClient = null;
private static boolean _useReflection =
( System.getProperty(REFLECTION_PROP) != null );
// ??? Security layer support not implemented
class SecureInputStream extends InputStream {
public SecureInputStream( InputStream is, Object saslClient ) {
_input = is;
_saslClient = saslClient;
}
public int read() throws IOException {
return _input.read();
}
private InputStream _input;
private Object _saslClient;
}
class SecureOutputStream extends OutputStream {
public SecureOutputStream( OutputStream os, Object saslClient ) {
_output = os;
_saslClient = saslClient;
}
public void write( int b ) throws IOException {
_output.write( b );
}
private OutputStream _output;
private Object _saslClient;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,619 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.io.Serializable;
import java.util.*;
/**
*
* Abstract class representing an element (such as an object class
* definition, an attribute type definition, or a matching rule
* definition) in the schema. The specific types of elements are
* represented by the <CODE>LDAPObjectClassSchema</CODE>,
* <CODE>LDAPAttributeSchema</CODE>, and <CODE>LDAPMatchingRuleSchema</CODE>
* subclasses.
* <P>
*
* <A HREF="http://ds.internic.net/rfc/rfc2252.txt"
* TARGET="_blank">RFC 2252, Lightweight Directory Access Protocol (v3):
* Attribute Syntax Definitions</A> covers the types of information
* that need to be specified in the definition of an object class,
* attribute type, or matching rule. All of these schema elements
* can specify the following information:
* <P>
*
* <UL>
* <LI>a name identifying the element
* <LI>an OID identifying the element
* <LI>a description of the element
* <LI>a qualifier "OBSOLETE"
* </UL>
* <P>
*
* In addition, there are optional standard qualifiers for attribute
* types (see LDAPAttributeSchema), and implementation-specific
* qualifiers may be added. Non-standard qualifiers must have names
* starting with X-, e.g. "X-OWNER 'John Jacobson'". Optional and
* non-standard qualifiers can be accessed with <CODE>getQualifier</CODE> and
* <CODE>setQualifier</CODE>, and enumerated with
* <CODE>getQualifierNames</CODE>.
* <P>
*
* The <CODE>LDAPSchemaElement</CODE> class implements methods that
* you can use with different types of schema elements (object class
* definitions, attribute type definitions, and matching rule definitions).
* You can do the following:
* <UL>
* <LI>get the name of a schema element
* <LI>get the OID of a schema element
* <LI>get the description of a schema element
* <LI>add an element to the schema
* <LI>remove an element from the schema
* </UL>
* <P>
*
* @see org.ietf.ldap.LDAPObjectClassSchema
* @see org.ietf.ldap.LDAPAttributeSchema
* @see org.ietf.ldap.LDAPMatchingRuleSchema
* @version 1.0
**/
public abstract class LDAPSchemaElement implements Serializable {
static final long serialVersionUID = -3972153461950418863L;
/**
* Constructs a blank element.
*/
protected LDAPSchemaElement() {
}
/**
* Constructs a definition explicitly
*
* @param names names of element
* @param oid dotted-string object identifier
* @param description description of element
*/
protected LDAPSchemaElement( String[] names,
String oid,
String description ) {
if ( oid == null ) {
throw new IllegalArgumentException( "OID required" );
}
this.names = names;
this.oid = oid;
this.description = description;
}
/**
* Gets the description of the object class, attribute type,
* or matching rule.
* @return the description of the object class, attribute type,
* or matching rule.
*/
public String getDescription() {
return description;
}
/**
* Gets the object ID (OID) of the object class, attribute type,
* or matching rule in dotted-string format (for example, "1.2.3.4").
* @return the OID of the object class, attribute type,
* or matching rule.
*/
public String getID() {
return oid;
}
/**
* Gets the names of the schema element
*
* @return the names of the schema element
*/
public String[] getNames() {
return names;
}
/**
* Gets the value of a qualifier which is not predefined.
* @param name name of qualifier
* @return value or values of qualifier; <CODE>null</CODE> if not
* present, a zero-length array if present but with no value.
*/
public String[] getQualifier( String name ) {
if ( properties == null ) {
return null;
}
Object o = properties.get( name );
if ( o == null ) {
return null;
}
if ( o instanceof Vector ) {
Vector v = (Vector)o;
String[] vals = new String[v.size()];
v.copyInto( vals );
return vals;
}
String s = (String)o;
if ( s.length() < 1 ) {
return new String[0];
} else {
return new String[] { s };
}
}
/**
* Gets an enumeration of all qualifiers which are not predefined.
* @return enumeration of qualifiers.
*/
public Enumeration getQualifierNames() {
return properties.keys();
}
/**
* Reports if the element is marked as obsolete.
* @return <CODE>true<CODE> if the element is defined as obsolete.
*/
public boolean isObsolete() {
return (properties == null) ? false :
properties.containsKey(OBSOLETE);
}
/**
* Keeps track of qualifiers which are not predefined.
* @param name name of qualifier
* @param value value of qualifier. "" for no value, <CODE>null</CODE>
* to remove the qualifier
*/
public void setQualifier( String name, String value ) {
if ( properties == null ) {
properties = new Hashtable();
}
if ( value != null ) {
properties.put( name, value );
} else {
properties.remove( name );
}
}
/**
* Keeps track of qualifiers which are not predefined.
* @param name name of qualifier
* @param values array of values
*/
public void setQualifier( String name, String[] values ) {
if ( values == null ) {
return;
}
if ( properties == null ) {
properties = new Hashtable();
}
Vector v = new Vector();
for( int i = 0; i < values.length; i++ ) {
v.addElement( values[i] );
}
properties.put( name, v );
}
/**
* Returns a String in a format suitable for directly adding to a
* Directory, as a value of the particular schema
* element attribute. See the format definition for each derived class
*
* @return Directory format of the schema element as a String
*/
public abstract String toString();
/**
* Parses a raw schema value into OID, name, description, and
* a Hashtable of other qualifiers and values.
*
* @param raw a raw schema definition
*/
protected void parseValue( String raw ) {
names = null;
if ( properties == null ) {
properties = new Hashtable();
}
int l = raw.length();
// Processing is faster in char array than in String
char[] ch = new char[l];
raw.getChars( 0, l, ch, 0 );
// Trim leading and trailing space
l--;
while( ch[l] == ' ' ) {
l--;
}
int start = 0;
while( ch[start] == ' ' ) {
start++;
}
// Skip past "( " and ")" to start of OID
start += 2;
// Find end of OID
int ind = start + 1;
while( ch[ind] != ' ' ) {
ind++;
}
oid = new String( ch, start, ind - start );
ind = ind + 1;
String s;
String val;
while ( ind < l ) {
// Skip past blanks to start of next token
while( ch[ind] == ' ' ) {
ind++;
}
// Find end of token
int last = ind + 1;
while( (last < l) && (ch[last] != ' ') )
last++;
if ( last < l ) {
// Found a token
s = new String( ch, ind, last-ind );
ind = last;
if ( novalsTable.containsKey( s ) ) {
properties.put( s, "" );
continue;
}
} else {
// Reached end of string with no end of token
s = "";
ind = l;
break;
}
// Find the start of the value of the token
while( (ind < l) && (ch[ind] == ' ') ) {
ind++;
}
last = ind + 1;
if ( ind >= l ) {
break;
}
boolean quoted = false;
boolean list = false;
if ( ch[ind] == '\'' ) {
// The value is quoted
quoted = true;
ind++;
while( (last < l) && (ch[last] != '\'') ) {
last++;
}
} else if ( ch[ind] == '(' ) {
// The value is a list
list = true;
ind++;
while( (last < l) && (ch[last] != ')') ) {
last++;
}
} else {
// The value is not quoted
while( (last < l) && (ch[last] != ' ') ) {
last++;
}
}
if ( (ind < last) && (last <= l) ) {
if ( list ) {
Vector v = new Vector();
if ( ch[ind] == ' ' ) {
ind++;
}
val = new String( ch, ind, last-ind-1 );
// Is this a quoted list? If so, use ' as delimiter,
// otherwise use ' '. The space between quoted
// values will be returned as tokens containing only
// white space. White space is not valid in a list
// value, so we just remove all tokens containing
// only white space.
String delim = (val.indexOf( '\'' ) >= 0) ? "'" : " ";
StringTokenizer st = new StringTokenizer( val, delim );
while ( st.hasMoreTokens() ) {
String tok = st.nextToken().trim();
if ( (tok.length() > 0) && !tok.equals( "$" ) ) {
v.addElement( tok );
}
}
properties.put( s, v );
} else {
val = new String( ch, ind, last-ind );
if ( s.equals( "NAME" ) ) {
names = new String[] { val };
} else if ( s.equals( "DESC" ) ) {
description = val;
} else {
properties.put( s, val );
}
if ( quoted ) {
last++;
}
}
}
ind = last + 1;
}
if ( names == null ) {
names = getQualifier( "NAME" );
if ( names == null ) {
names = new String[0];
}
}
}
/**
* Gets the attribute name for a schema element
*
* @return The attribute name of the element
*/
String getAttributeName() {
return null;
}
/**
* Formats a String in the format defined in X.501 (see
* <A HREF="http://ds.internic.net/rfc/rfc2252.txt"
* >RFC 2252, Lightweight Directory Access Protocol
* (v3): Attribute Syntax Definitions</A>
* for a description of this format).
* This is the format that LDAP servers and clients use to exchange
* schema information. For example, when
* you search an LDAP server for its schema, the server returns an entry
* with the attributes "objectclasses" and "attributetypes". The
* values of the "attributetypes" attribute are attribute type
* descriptions in this format.
* <P>
* @param quotingBug <CODE>true</CODE> if single quotes are to be
* supplied around the SYNTAX and SUP value
* @return a formatted String for defining a schema element.
*/
String getValue() {
return getValue( false );
}
String getValue( boolean quotingBug ) {
return null;
}
/**
* Prepares the initial common part of a schema element value in
* RFC 2252 format for submitting to a server
*
* @return the OID, name, description, and possibly OBSOLETE
* fields of a schema element definition.
*/
String getValuePrefix() {
String s = "( " + oid + ' ';
s += getNameField();
if ( description != null ) {
s += "DESC \'" + description + "\' ";
}
if ( isObsolete() ) {
s += OBSOLETE + ' ';
}
return s;
}
String getNameField() {
String s = "";
if ( (names != null) && (names.length > 0) ) {
s += "NAME ";
if ( names.length > 1 ) {
s += "( ";
}
for( int i = 0; i < names.length; i++ ) {
s += '\'' + names[i] + "\' ";
}
if ( names.length > 1 ) {
s += ") ";
}
}
return s;
}
/**
* Gets qualifiers which may or may not be present
*
* @param names list of qualifiers to look up
* @return String in RFC 2252 format containing any values
* found, not terminated with ' '.
*/
protected String getOptionalValues( String[] names ) {
String s = "";
for( int i = 0; i < names.length; i++ ) {
String[] vals = getQualifier( names[i] );
if ( (vals != null) && (vals.length > 0) ) {
s += names[i] + ' ' + vals[0];
}
}
return s;
}
/**
* Gets any qualifiers marked as custom (starting with "X-")
*
* @return string in RFC 2252 format, without a terminating
* ' '.
*/
protected String getCustomValues() {
String s = "";
Enumeration en = properties.keys();
while( en.hasMoreElements() ) {
String key = (String)en.nextElement();
if ( !key.startsWith( "X-" ) ) {
continue;
}
s += getValue( key, true, false ) + ' ';
}
// Strip trailing ' '
if ( (s.length() > 0) && (s.charAt( s.length() - 1 ) == ' ') ) {
s = s.substring( 0, s.length() - 1 );
}
return s;
}
/**
* Gets a qualifier's value or values, if present, and formats
* the String according to RFC 2252
*
* @param key the qualifier to get
* @param doQuote <CODE>true</CODE> if values should be enveloped
* with single quotes
* @param doDollar <CODE>true</CODE> if a list of values should use
* " $ " as separator; that is true for object class attribute lists
* @return String in RFC 2252 format, without a terminating
* ' '.
*/
String getValue( String key, boolean doQuote, boolean doDollar ) {
String s = "";
Object o = properties.get( key );
if ( o == null ) {
return s;
}
if ( o instanceof String ) {
if ( ((String)o).length() > 0 ) {
s += key + ' ';
if ( doQuote ) {
s += '\'';
}
s += (String)o;
if ( doQuote ) {
s += '\'';
}
}
} else {
s += key + " ( ";
Vector v = (Vector)o;
for( int i = 0; i < v.size(); i++ ) {
if ( doQuote ) {
s += '\'';
}
s += (String)v.elementAt(i);
if ( doQuote ) {
s += '\'';
}
s += ' ';
if ( doDollar && (i < (v.size() - 1)) ) {
s += "$ ";
}
}
s += ')';
}
return s;
}
/**
* Gets a qualifier's value or values, if present, and format
* the String according to RFC 2252.
*
* @param key the qualifier to get
* @param doQuote <CODE>true</CODE> if values should be enveloped
* with single quotes
* @return String in RFC 2252 format, without a terminating
* ' '.
*/
String getValue( String key, boolean doQuote ) {
return getValue( key, doQuote, true );
}
/**
* Creates a string for use in toString with any qualifiers of the element.
*
* @param ignore any qualifiers to NOT include
* @return a String with any known qualifiers.
*/
String getQualifierString( String[] ignore ) {
Hashtable toIgnore = null;
if ( ignore != null ) {
toIgnore = new Hashtable();
for( int i = 0; i < ignore.length; i++ ) {
toIgnore.put( ignore[i], ignore[i] );
}
}
String s = "";
Enumeration en = getQualifierNames();
while( en.hasMoreElements() ) {
String qualifier = (String)en.nextElement();
if ( (toIgnore != null) && toIgnore.containsKey( qualifier ) ) {
continue;
}
s += "; " + qualifier;
String[] vals = getQualifier( qualifier );
if ( vals == null ) {
s += ' ';
continue;
}
s += ": ";
for( int i = 0; i < vals.length; i++ ) {
s += vals[i] + ' ';
}
}
// Strip trailing ' '
if ( (s.length() > 0) && (s.charAt( s.length() - 1 ) == ' ') ) {
s = s.substring( 0, s.length() - 1 );
}
return s;
}
// Constants for known syntax types
public static final int unknown = 0;
public static final int cis = 1;
public static final int binary = 2;
public static final int telephone = 3;
public static final int ces = 4;
public static final int dn = 5;
public static final int integer = 6;
protected static final String cisString =
"1.3.6.1.4.1.1466.115.121.1.15";
protected static final String binaryString =
"1.3.6.1.4.1.1466.115.121.1.5";
protected static final String telephoneString =
"1.3.6.1.4.1.1466.115.121.1.50";
protected static final String cesString =
"1.3.6.1.4.1.1466.115.121.1.26";
protected static final String intString =
"1.3.6.1.4.1.1466.115.121.1.27";
protected static final String dnString =
"1.3.6.1.4.1.1466.115.121.1.12";
// Predefined qualifiers which apply to any schema element type
public static final String OBSOLETE = "OBSOLETE";
public static final String SUPERIOR = "SUP";
// Predefined qualifiers
public static final String SYNTAX = "SYNTAX";
// Properties which are common to all schema elements
protected String oid = null;
protected String description = "";
protected String attrName = null;
protected String rawValue = null;
protected String[] names = new String[0];
// Additional qualifiers
protected Hashtable properties = null;
// Qualifiers known to not have values
static protected Hashtable novalsTable = new Hashtable();
}

View File

@@ -0,0 +1,268 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
/**
* Represents a set of search preferences.
* You can set these preferences for a particular search
* by creating an <CODE>LDAPSearchConstraints</CODE> object,
* specifying your preferences, and passing the object to
* the <CODE>LDAPConnection.search</CODE> method.
* <P>
*
* @version 1.0
*/
public class LDAPSearchConstraints extends LDAPConstraints {
private int deref;
private int maxRes;
private int batch;
private int serverTimeLimit;
private int maxBacklog = 100;
/**
* Constructs an object with the default set of search constraints
*/
public LDAPSearchConstraints() {
super();
deref = 0;
maxRes = 1000;
batch = 1;
serverTimeLimit = 0;
}
/**
* Constructs an object with the supplied constraints as template
*/
public LDAPSearchConstraints( LDAPConstraints cons ) {
this();
setHopLimit( cons.getHopLimit() );
setReferralFollowing( cons.getReferralFollowing() );
setTimeLimit( cons.getTimeLimit() );
setReferralHandler( cons.getReferralHandler());
LDAPControl[] tServerControls = cons.getControls();
if ( (tServerControls != null) &&
(tServerControls.length > 0) ) {
LDAPControl[] oServerControls =
new LDAPControl[tServerControls.length];
for( int i = 0; i < tServerControls.length; i++ ) {
oServerControls[i] = (LDAPControl)tServerControls[i].clone();
}
setControls(oServerControls);
}
if ( cons instanceof LDAPSearchConstraints ) {
LDAPSearchConstraints scons = (LDAPSearchConstraints)cons;
setServerTimeLimit( scons.getServerTimeLimit() );
setDereference( scons.getDereference() );
setMaxResults( scons.getMaxResults() );
setBatchSize( scons.getBatchSize() );
setMaxBacklog( scons.getMaxBacklog() );
}
}
/**
* Constructs a new <CODE>LDAPSearchConstraints</CODE> object and allows you
* to specify the search constraints in that object.
* <P>
* @param msLimit maximum time in milliseconds to wait for results (0
* by default, which means that there is no maximum time limit)
* @param timeLimit maximum time in seconds for the server to spend
* processing a search request (the default value is 0, indicating that there
* is no limit)
* @param dereference either <CODE>LDAPConnection.DEREF_NEVER</CODE>,
* <CODE>LDAPConnection.DEREF_FINDING</CODE>,
* <CODE>LDAPConnection.DEREF_SEARCHING</CODE>, or
* <CODE>LDAPConnection.DEREF_ALWAYS</CODE> (see LDAPConnection.setOption).
* <CODE>LDAPConnection.DEREF_NEVER</CODE> is the default.
* @param maxResults maximum number of search results to return
* (1000 by default)
* @param doReferrals specify <CODE>true</CODE> to follow referrals
* automatically, or <CODE>false</CODE> to throw an
* <CODE>LDAPReferralException</CODE> error if the server sends back
* a referral (<CODE>false</CODE> by default)
* @param batchSize specify the number of results to return at a time
* (1 by default)
* @param bind_proc specifies the object that
* implements the <CODE>LDAPBind</CODE> interface (you need to
* define this class). The object will be used to authenticate
* to the server on referrals.
* (This field is <CODE>null</CODE> by default.)
* @param hop_limit maximum number of referrals to follow in a
* sequence when attempting to resolve a request
* @see org.ietf.ldap.LDAPConnection#setOption(int, java.lang.Object)
* @see org.ietf.ldap.LDAPConnection#search(org.ietf.ldap.LDAPUrl, org.ietf.ldap.LDAPSearchConstraints)
* @see org.ietf.ldap.LDAPConnection#search(java.lang.String, int, java.lang.String, java.lang.String[], boolean, org.ietf.ldap.LDAPSearchConstraints)
*/
public LDAPSearchConstraints( int msLimit,
int timeLimit,
int dereference,
int maxResults,
boolean doReferrals,
int batchSize,
LDAPReferralHandler handler,
int hop_limit) {
super( msLimit, doReferrals, handler, hop_limit );
serverTimeLimit = timeLimit;
deref = dereference;
maxRes = maxResults;
batch = batchSize;
}
/**
* Returns the suggested number of results to return at a time during
* search. This should be 0 if intermediate results are not needed, and
* 1 if results are to be processed as they come in.
* @return number of results to return at a time.
*/
public int getBatchSize() {
return batch;
}
/**
* Specifies how aliases should be dereferenced.
* @return <CODE>LDAPConnection.DEREF_NEVER</CODE> to
* never follow ("dereference") aliases,
* <CODE>LDAPConnection.DEREF_FINDING</CODE> to dereference when finding
* the starting point for the search (but not when searching
* under that starting entry), <CODE>LDAPConnection.DEREF_SEARCHING</CODE>
* to dereference when searching the entries beneath the
* starting point of the search (but not when finding the starting
* entry), or <CODE>LDAPConnection.DEREF_ALWAYS</CODE> to always
* dereference aliases.
*/
public int getDereference() {
return deref;
}
/**
* Get the maximum number of unread entries any search listener can
* have before we stop reading from the server.
* @return the maximum number of unread entries per listener.
* @deprecated Use <CODE>LDAPConnection.getOption()</CODE>
*/
public int getMaxBacklog() {
return maxBacklog;
}
/**
* Returns the maximum number of search results that are to be returned; 0 means
* there is no limit.
* @return maximum number of search results to be returned.
*/
public int getMaxResults() {
return maxRes;
}
/**
* Returns the maximum number of seconds to wait for the server to
* spend on a search operation.If 0, there is no time limit.
* @return maximum number of seconds for the server to spend.
*/
public int getServerTimeLimit() {
return serverTimeLimit;
}
/**
* Sets the suggested number of results to return at a time during search.
* This should be 0 if intermediate results are not needed, and 1 if
* results are to be processed as they come in. (By default, this is 1.)
* @param batchSize number of results to return at a time
*/
public void setBatchSize( int batchSize ) {
batch = batchSize;
}
/**
* Sets a preference indicating how aliases should be dereferenced.
* @param dereference <CODE>LDAPConnection.DEREF_NEVER</CODE> to
* never follow ("dereference") aliases,
* <CODE>LDAPConnection.DEREF_FINDING</CODE> to dereference when finding
* the starting point for the search (but not when searching
* under that starting entry), <CODE>LDAPConnection.DEREF_SEARCHING</CODE>
* to dereference when searching the entries beneath the
* starting point of the search (but not when finding the starting
* entry), or <CODE>LDAPConnection.DEREF_ALWAYS</CODE> to always
* dereference aliases
*/
public void setDereference( int dereference ) {
deref = dereference;
}
/**
* Set the maximum number of unread entries any search listener can
* have before we stop reading from the server.
* @param backlog the maximum number of unread entries per listener
* @deprecated Use <CODE>LDAPConnection.setOption()</CODE>
*/
public void setMaxBacklog( int backlog ) {
maxBacklog = backlog;
}
/**
* Sets the maximum number of search results to return; 0 means
* there is no limit. (By default, this is set to 1000.)
* @param maxResults maximum number of search results to return
*/
public void setMaxResults( int maxResults ) {
maxRes = maxResults;
}
/**
* Sets the maximum number of seconds for the server to spend
* returning search results. If 0, there is no time limit.
* @param limit maximum number of seconds for the server to spend.
* (0 by default, which means that there is no maximum time limit.)
*/
public void setServerTimeLimit( int limit ) {
serverTimeLimit = limit;
}
/**
* Makes a copy of an existing set of search constraints.
* @return a copy of an existing set of search constraints.
*/
public Object clone() {
return new LDAPSearchConstraints( this );
}
/**
* Return a string representation of the object for debugging
*
* @return A string representation of the object
*/
public String toString() {
StringBuffer sb = new StringBuffer("LDAPSearchConstraints {");
sb.append( super.toString() + ' ' );
sb.append("size limit " + maxRes + ", ");
sb.append("server time limit " + serverTimeLimit + ", ");
sb.append("aliases " + deref + ", ");
sb.append("batch size " + batch + ", ");
sb.append("max backlog " + maxBacklog);
sb.append('}');
return sb.toString();
}
}

View File

@@ -0,0 +1,202 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.io.Serializable;
import java.util.*;
import org.ietf.ldap.client.*;
/**
* Manages search results, references and responses returned on one or
* more search requests
*
*/
public class LDAPSearchQueue extends LDAPMessageQueueImpl {
static final long serialVersionUID = -7163312406176592277L;
/**
* Constructs a search message queue
*
* @param asynchOp a boolean flag indicating whether the object is used
* for asynchronous LDAP operations
* @param cons LDAP search constraints
* @see org.ietf.ldap.LDAPAsynchronousConnection
*/
LDAPSearchQueue( boolean asynchOp,
LDAPSearchConstraints cons ) {
super( asynchOp );
_constraints = cons;
}
/**
* Blocks until a search result, reference or response is available,
* or until all operations associated with the object have completed
* or been canceled.
* Wakes up the LDAPConnThread if the backlog limit has been reached.
*
* @return a search result, search reference, search response message,
* or null if there are no more outstanding requests.
* @exception LDAPException Network error exception
* @exception LDAPInterruptedException The invoking thread was interrupted
* @see LDAPResponse
* @see LDAPSearchResult
* @see LDAPSearchResultReference
*/
public LDAPMessage getResponse() throws LDAPException{
LDAPMessage result = super.getResponse();
// Notify LDAPConnThread to wake up if backlog limit has been reached
if ( result instanceof LDAPSearchResult ||
result instanceof LDAPSearchResultReference ) {
LDAPConnThread connThread =
getConnThread( result.getMessageID() );
if ( connThread != null ) {
connThread.resultRetrieved();
}
}
return result;
}
/**
* Blocks until a response is available for a particular message ID, or
* until all operations associated with the message ID have completed or
* been canceled, and returns the response. If there is no outstanding
* operation for the message ID (or if it is zero or a negative number),
* IllegalArgumentException is thrown.
*
* @param msgid A particular message to query for responses available
* @return a response for an LDAP operation or null if there are no
* more outstanding requests.
* @exception LDAPException Network error exception
* @exception LDAPInterruptedException The invoking thread was interrupted
*/
public LDAPMessage getResponse( int msgid )
throws LDAPException {
LDAPMessage result = super.getResponse( msgid );
// Notify LDAPConnThread to wake up if backlog limit has been reached
if ( result instanceof LDAPSearchResult ||
result instanceof LDAPSearchResultReference ) {
LDAPConnThread connThread =
getConnThread( result.getMessageID() );
if ( connThread != null ) {
connThread.resultRetrieved();
}
}
return result;
}
/**
* Reports true if all results for a particular message ID have been
* received by the API implementation. That is the case if a
* searchResultDone response has been received by the SDK. There may
* still be messages queued in the object for retrieval by the
* application. If there is no outstanding operation for the message ID
* (or if it is zero or a negative number), IllegalArgumentException is
* thrown.
*
* @param msgid A particular message to query for completion
* @return true if all results for a particular message ID have been
* received
*/
public synchronized boolean isComplete( int msgid ) throws LDAPException {
boolean OK = false;
for ( int i = (_messageQueue.size()-1); i >= 0; i-- ) {
LDAPMessage msg = (LDAPMessage)_messageQueue.get(i);
if ( msg.getMessageID() == msgid ) {
OK = true;
break;
}
}
if ( !OK ) {
throw new IllegalArgumentException( "Invalid msg ID: " + msgid );
}
// Search an instance of LDAPResponse
for ( int i = _messageQueue.size()-1; i >= 0; i-- ) {
LDAPMessage msg = (LDAPMessage)_messageQueue.get(i);
if ( msg instanceof LDAPResponse ) {
return true;
}
}
return false;
}
/**
* Gets the key of the cache entry
*
* @return the key of the cache entry
*/
Long getKey() {
return _key;
}
/**
* Returns the search constraints used to create this object.
*
* @return the search constraints used to create this object.
*/
LDAPSearchConstraints getSearchConstraints() {
return _constraints;
}
/**
* Resets the state of this object so it can be recycled
* Used by LDAPConnection synchronous operations.
*/
void reset() {
super.reset();
_constraints = null;
}
/**
* Sets the key of the cache entry. The queue needs to know this value
* when the results get processed. After the results have been
* saved in the vector, then the key and a vector of results are put in
* the cache.
*
* @param key the key of the cache entry
*/
void setKey( Long key ) {
_key = key;
}
/**
* Sets search constraints
*
* @param cons LDAP search constraints
*/
void setSearchConstraints( LDAPSearchConstraints cons ) {
_constraints = cons;
}
// this instance variable is only for cache purposes
private Long _key = null;
private LDAPSearchConstraints _constraints;
}

View File

@@ -0,0 +1,77 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import org.ietf.ldap.client.opers.JDAPSearchResponse;
/**
* A LDAPSearchResult object encapsulates a single search result.
*
* @version 1.0
*/
public class LDAPSearchResult extends LDAPMessage {
static final long serialVersionUID = 36890821518462301L;
/**
* LDAPEntry
*/
private LDAPEntry _entry;
/**
* Constructor
*
* @param msgid message identifier
* @param rsp search operation response
* @param controls array of controls or null
* @see org.ietf.ldap.LDAPEntry
*/
LDAPSearchResult( int msgid,
JDAPSearchResponse rsp,
LDAPControl[]controls ) {
super( msgid, rsp, controls );
}
/**
* Returns the entry of a server search response
*
* @return an entry returned by the server in response to a search
* request
* @see org.ietf.ldap.LDAPEntry
*/
public LDAPEntry getEntry() {
if (_entry == null) {
JDAPSearchResponse rsp = (JDAPSearchResponse)getProtocolOp();
LDAPAttribute[] lattrs = rsp.getAttributes();
LDAPAttributeSet attrs;
if ( lattrs != null ) {
attrs = new LDAPAttributeSet( lattrs );
}
else {
attrs = new LDAPAttributeSet();
}
String dn = rsp.getObjectName();
_entry = new LDAPEntry( dn, attrs );
}
return _entry;
}
}

View File

@@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import org.ietf.ldap.client.opers.JDAPSearchResultReference;
/**
* An LDAPSearchResultReference object encapsulates a continuation
* reference from a search operation.
*
* @version 1.0
*/
public class LDAPSearchResultReference extends LDAPMessage {
static final long serialVersionUID = -7816778029315223117L;
/**
* A list of LDAP URLs that are referred to.
*/
private String _URLs[];
/**
* Constructor
*
* @param msgid message identifier
* @param resRef search result reference response
* @param controls array of controls or null
* @see org.ietf.ldap.LDAPEntry
*/
LDAPSearchResultReference( int msgid,
JDAPSearchResultReference resRef,
LDAPControl[]controls ) {
super( msgid, resRef, controls );
_URLs = resRef.getUrls();
}
/**
* Returns a list of LDAP URLs that are referred to
*
* @return a list of URLs.
*/
public String[] getReferrals() {
return _URLs;
}
}

View File

@@ -0,0 +1,584 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
import org.ietf.ldap.client.*;
import org.ietf.ldap.client.opers.*;
import java.io.*;
/**
* The results of an LDAP search operation, represented as an enumeration.
* Note that you can only iterate through this enumeration once: if you
* need to use these results more than once, make sure to save the
* results in a separate location.
* <P>
*
* You can also use the results of a search in progress to abandon that search
* operation.
* <P>
*
* @version 1.0
* @see org.ietf.ldap.LDAPConnection#search(java.lang.String, int, java.lang.String, java.lang.String[], boolean)
* @see org.ietf.ldap.LDAPConnection#abandon(org.ietf.ldap.LDAPSearchResults)
*/
public class LDAPSearchResults implements Serializable {
static final long serialVersionUID = -501692208613904825L;
private Vector entries = null;
private LDAPSearchQueue resultSource;
private boolean searchComplete = false;
private LDAPConnection connectionToClose;
private LDAPConnection currConn;
private boolean persistentSearch = false;
private LDAPSearchConstraints currCons;
private String currBase;
private int currScope;
private String currFilter;
private String[] currAttrs;
private boolean currAttrsOnly;
private Vector referralResults = new Vector();
private Vector exceptions;
private int msgID = -1;
// only used for the persistent search
private boolean firstResult = false;
/**
* Constructs an enumeration of search results.
* Note that this does not actually generate the results;
* you need to call <CODE>LDAPConnection.search</CODE> to
* perform the search and get the results.
* @see org.ietf.ldap.LDAPConnection#search(java.lang.String, int, java.lang.String, java.lang.String[], boolean)
*/
public LDAPSearchResults() {
entries = new Vector();
connectionToClose = null;
searchComplete = true;
currCons = new LDAPSearchConstraints();
}
LDAPSearchResults( LDAPConnection conn,
LDAPSearchConstraints cons,
String base,
int scope,
String filter,
String[] attrs,
boolean attrsOnly ) {
this();
currConn = conn;
currCons = cons;
currBase = base;
currScope = scope;
currFilter = filter;
currAttrs = attrs;
currAttrsOnly = attrsOnly;
}
/**
* Constructs an enumeration of search results. Used when returning results
* from a cache.
* @param v the vector containing LDAPEntries
* @see org.ietf.ldap.LDAPConnection#search(java.lang.String, int, java.lang.String, java.lang.String[], boolean)
*/
LDAPSearchResults( Vector v ) {
this();
entries = (Vector)v.clone();
if ((entries != null) && (entries.size() >= 1)) {
// Each cache value is represented by a vector. The first element
// represents the size of all the LDAPEntries. This needs to be
// removed before we iterate through each LDAPEntry.
entries.removeElementAt(0);
}
}
LDAPSearchResults( Vector v,
LDAPConnection conn,
LDAPSearchConstraints cons,
String base,
int scope,
String filter,
String[] attrs,
boolean attrsOnly ) {
this( v );
currConn = conn;
currCons = cons;
currBase = base;
currScope = scope;
currFilter = filter;
currAttrs = attrs;
currAttrsOnly = attrsOnly;
}
/**
* Returns a count of queued search results immediately available for
* processing.
* A search result is either a search entry or an exception. If the
* search is asynchronous (batch size not 0), this reports the number
* of results received so far.
* @return count of search results immediatly available for processing
*/
public int getCount() {
while (resultSource != null && resultSource.getMessageCount() > 0) {
fetchResult();
}
int count = entries.size();
for ( int i = 0; i < referralResults.size(); i++ ) {
LDAPSearchResults res =
(LDAPSearchResults)referralResults.elementAt(i);
count += res.getCount();
}
if ( exceptions != null ) {
count += exceptions.size();
}
return count;
}
/**
* Returns the controls returned with this search result. If any control
* is registered with <CODE>LDAPControl</CODE>, an attempt is made to
* instantiate the control. If the instantiation fails, the control is
* returned as a basic <CODE>LDAPControl</CODE>.
* @return an array of type <CODE>LDAPControl</CODE>.
* @see org.ietf.ldap.LDAPControl#register
*/
public LDAPControl[] getResponseControls() {
return currConn.getResponseControls(msgID);
}
/**
* Returns <CODE>true</CODE> if there are more search results
* to be returned. You can use this method in conjunction with the
* <CODE>next</CODE> or <CODE>next</CODE> methods to iterate
* through each entry in the results. For example:
* <PRE>
* LDAPSearchResults res = ld.search( MY_SEARCHBASE,
* LDAPConnection.SCOPE_BASE, MY_FILTER,
* null, false );
* while ( res.hasMore() ) {
* LDAPEntry findEntry = res.next();
* ...
* }
* </PRE>
* @return <CODE>true</CODE> if there are more search results.
* @see org.ietf.ldap.LDAPSearchResults#next()
*/
public boolean hasMore() {
while ((entries.size() == 0) && (!searchComplete)) {
fetchResult();
}
if ((entries.size() == 0) &&
((exceptions == null) || (exceptions.size() == 0))) {
while (referralResults.size() > 0) {
LDAPSearchResults res =
(LDAPSearchResults)referralResults.elementAt(0);
if (res.hasMore())
return true;
else
referralResults.removeElementAt(0);
}
}
return ((entries.size() > 0) ||
((exceptions != null) && (exceptions.size() > 0)));
}
/**
* Returns the next LDAP entry from the search results
* and throws an exception if the next result is a referral, or
* if a sizelimit or timelimit error occurred.
* <P>
*
* You can use this method in conjunction with the
* <CODE>hasMore</CODE> method to iterate through
* each entry in the search results. For example:
* <PRE>
* LDAPSearchResults res = ld.search( MY_SEARCHBASE,
* LDAPConnection.SCOPE_BASE, MY_FILTER,
* null, false );
* while ( res.has() ) {
* try {
* LDAPEntry findEntry = res.next();
* } catch ( LDAPReferralException e ) {
* String refUrls[] = e.getReferrals();
* for ( int i = 0; i < refUrls.length; i++ ) {
* // Your code for handling referrals
* }
* continue;
* } catch ( LDAPException e ) {
* // Your code for handling errors on limits exceeded
* continue;
* }
* ...
* }
* </PRE>
* @return the next LDAP entry in the search results.
* @exception LDAPReferralException A referral (thrown
* if the next result is a referral), or LDAPException
* if a limit on the number of entries or the time was
* exceeded.
* @see org.ietf.ldap.LDAPSearchResults#hasMore()
*/
public LDAPEntry next() throws LDAPException {
Object o = nextElement();
if ((o instanceof LDAPReferralException) ||
(o instanceof LDAPException)) {
throw (LDAPException)o;
}
if (o instanceof LDAPEntry) {
return (LDAPEntry)o;
}
return null;
}
/**
* Sorts the search results.
* <P>
*
* The comparator determines the sort order used. For example, if the
* comparator uses the <CODE>uid</CODE>
* attribute for comparison, the search results are sorted according to
* <CODE>uid</CODE>.
* <P>
*
* The following section of code sorts results in ascending order,
* first by surname and then by common name.
*
* <PRE>
* String[] sortAttrs = {"sn", "cn"};
* boolean[] ascending = {true, true};
*
* LDAPConnection ld = new LDAPConnection();
* ld.connect( ... );
* LDAPSearchResults res = ld.search( ... );
* res.sort( new LDAPCompareAttrNames(sortAttrs, ascending) );
* </PRE>
* NOTE: If the search results arrive asynchronously, the <CODE>sort</CODE>
* method blocks until all the results are returned.
* <P>
*
* If some of the elements of the Enumeration have already been fetched,
* the cursor is reset to the (new) first element.
* <P>
*
* @param compare comparator used to determine the sort order of the results
* @see LDAPCompareAttrNames
*/
public synchronized void sort(Comparator compare) {
// if automatic referral, then add to the entries, otherwise, dont do it
// since the elements in referralResults are LDAPReferralException.
if (currCons.getReferralFollowing()) {
while (referralResults.size() > 0) {
Object obj = null;
if ((obj=nextReferralElement()) != null) {
if (obj instanceof LDAPException) {
add((LDAPException)obj); // put it back
}
else {
entries.addElement(obj);
}
}
}
}
int numEntries = entries.size();
if (numEntries <= 0) {
return;
}
LDAPEntry[] toSort = new LDAPEntry[numEntries];
entries.copyInto (toSort);
if (toSort.length > 1) {
quicksort (toSort, compare, 0, numEntries-1);
}
entries.removeAllElements();
for (int i = 0; i < numEntries; i++) {
entries.addElement (toSort[i]);
}
}
/**
* Adds a search entry or referral
*
* @param msg LDAPSearchResult or LDAPsearchResultReference
*/
void add( LDAPMessage msg ) {
if ( msg instanceof LDAPSearchResult ) {
entries.addElement( ((LDAPSearchResult)msg).getEntry());
} else if ( msg instanceof LDAPSearchResultReference ) {
/* convert to LDAPReferralException */
String urls[] = ((LDAPSearchResultReference)msg).getReferrals();
if ( urls != null ) {
if (exceptions == null) {
exceptions = new Vector();
}
exceptions.addElement(
new LDAPReferralException(null, 0, urls) );
}
}
}
/**
* Adds and exception
* @param e exception
*/
void add( LDAPException e ) {
if ( exceptions == null ) {
exceptions = new Vector();
}
exceptions.addElement( e );
}
/**
* Prepares to return asynchronous results from a search
*
* @param l Listener which will provide results
*/
void associate( LDAPSearchQueue l ) {
resultSource = l;
searchComplete = false;
}
void associatePersistentSearch( LDAPSearchQueue l) {
resultSource = l;
persistentSearch = true;
searchComplete = false;
firstResult = true;
}
void addReferralEntries( LDAPSearchResults res ) {
referralResults.addElement( res );
}
/**
* For asynchronous search, this mechanism allows the programmer to
* close a connection whenever the search completes.
* @param toClose connection to close when the search terminates
*/
void closeOnCompletion( LDAPConnection toClose ) {
if ( searchComplete ) {
try {
toClose.disconnect();
} catch( LDAPException e ) {
}
} else {
connectionToClose = toClose;
}
}
/**
* Basic quicksort algorithm.
*/
void quicksort ( LDAPEntry[] toSort, Comparator compare,
int low, int high ) {
if (low >= high) {
return;
}
LDAPEntry pivot = toSort[low];
int slow = low-1, shigh = high+1;
while (true) {
do {
shigh--;
} while ( compare.compare(toSort[shigh], pivot) > 0 );
do {
slow++;
} while ( compare.compare(pivot, toSort[slow]) > 0 );
if (slow >= shigh) {
break;
}
LDAPEntry temp = toSort[slow];
toSort[slow] = toSort[shigh];
toSort[shigh] = temp;
}
quicksort (toSort, compare, low, shigh);
quicksort (toSort, compare, shigh+1, high);
}
/**
* Sets the message ID for this search request. msgID is used
* to retrieve response controls.
* @param msgID Message ID for this search request
*/
void setMsgID( int msgID ) {
this.msgID = msgID;
}
/**
* Returns the next result from a search. You can use this method
* in conjunction with the <CODE>hasMore</CODE> method to
* iterate through all elements in the search results.
* <P>
*
* Make sure to cast the
* returned element as the correct type. For example:
* <PRE>
* LDAPSearchResults res = ld.search( MY_SEARCHBASE,
* LDAPConnection.SCOPE_BASE, MY_FILTER,
* null, false );
* while ( res.hasMore() ) {
* Object o = res.next();
* if ( o instanceof LDAPEntry ) {
* LDAPEntry findEntry = (LDAPEntry)o;
* ...
* } else if ( o instanceof LDAPReferralException ) {
* LDAPReferralException e = (LDAPReferralException)o;
* String refUrls[] = e.getReferrals();
* ...
* } else if ( o instanceof LDAPException ) {
* LDAPException e = (LDAPException)o;
* ...
* }
* }
* </PRE>
* @return the next element in the search results.
* @see org.ietf.ldap.LDAPSearchResults#hasMore()
*/
Object nextElement() {
if ( entries.size() > 0 ) {
Object obj = entries.elementAt(0);
entries.removeElementAt(0);
return obj;
}
if (referralResults.size() > 0) {
return nextReferralElement();
}
if ((exceptions != null) && (exceptions.size() > 0)) {
Object obj = exceptions.elementAt(0);
exceptions.removeElementAt(0);
return obj;
}
return null;
}
Object nextReferralElement() {
LDAPSearchResults res =
(LDAPSearchResults)referralResults.elementAt(0);
if ((!res.persistentSearch && res.hasMore()) ||
(res.persistentSearch)) {
Object obj = res.nextElement();
if (obj != null) {
return obj;
}
if ((obj == null) || (!res.hasMore())) {
referralResults.removeElementAt(0);
}
} else {
referralResults.removeElementAt(0);
}
return null;
}
/**
* Returns message ID.
* @return Message ID.
*/
int getMessageID() {
if ( resultSource == null ) {
return -1;
}
return resultSource.getMessageID();
}
/**
* Fetchs the next result, for asynchronous searches.
*/
private synchronized void fetchResult() {
/* Asynchronous case */
if ( resultSource != null ) {
synchronized( this ) {
if (searchComplete || firstResult) {
firstResult = false;
return;
}
LDAPMessage msg = null;
try {
msg = resultSource.getResponse();
} catch (LDAPException e) {
add(e);
currConn.releaseSearchListener(resultSource);
searchComplete = true;
return;
}
if (msg == null) { // Request abandoned
searchComplete = true;
currConn.releaseSearchListener(resultSource);
return;
} else if (msg instanceof LDAPResponse) {
try {
// check response and see if we need to do referral
// v2: referral stored in the JDAPResult
currConn.checkSearchMsg(this, msg, currCons,
currBase, currScope, currFilter,
currAttrs, currAttrsOnly);
} catch (LDAPException e) {
System.err.println("LDAPSearchResults.fetchResult: "+e);
} finally {
currConn.releaseSearchListener(resultSource);
}
searchComplete = true;
if (connectionToClose != null) {
try {
connectionToClose.disconnect ();
} catch (LDAPException e) {
}
connectionToClose = null;
}
return;
} else {
try {
currConn.checkSearchMsg(this, msg, currCons,
currBase, currScope, currFilter, currAttrs, currAttrsOnly);
} catch (LDAPException e) {
System.err.println("Exception: "+e);
}
}
}
}
}
}

View File

@@ -0,0 +1,59 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
import java.io.*;
import java.net.*;
/**
* Represents a socket connection that you can use to connect to an
* LDAP server. You can write a class that implements this interface
* if you want to use a TLS socket to connect to a secure server.
* (The <CODE>LDAPSSLSocketFactory class</CODE>, which is included
* in the <CODE>org.ietf.ldap</CODE> package, implements this
* interface for SSL connections.)
* <P>
*
* When you construct a new <CODE>LDAPConnection</CODE>
* object, you can specify that the connection use this socket.
* To do this, pass the constructor an object of the class that
* implements this interface.
* <P>
*
* @version 1.0
* @see LDAPConnection#LDAPConnection(org.ietf.ldap.LDAPSocketFactory)
* @see LDAPSSLSocketFactory
*/
public interface LDAPSocketFactory {
/**
* Returns a socket to the specified host name and port number.
* <P>
*
* @param host name of the host to which you want to connect
* @param port port number to which you want to connect
* @exception LDAPException Failed to create the socket.
* @see LDAPSSLSocketFactory#createSocket(java.lang.String,int)
*/
public Socket createSocket( String host, int port )
throws LDAPException;
}

View File

@@ -0,0 +1,169 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
/**
* Represents sorting instructions for a particular attribute.
*
* @version 1.0
*/
public class LDAPSortKey implements java.io.Serializable {
static final long serialVersionUID = -7044232342344864405L;
public final static int REVERSE = 0x81;
/**
* Constructs a new <CODE>LDAPSortKey</CODE> object that will
* sort based on the specified instructions.
* @param keyDescription a single attribute specification by which to sort
* If preceded by a hyphen ("-"), the attribute is sorted in reverse order.
* You can also specify the object ID (OID) of a matching rule after
* a colon (":"). For example:
* <P>
* <UL>
* <LI><CODE>"cn"</CODE> (sort by the <CODE>cn</CODE> attribute) <P>
* <LI><CODE>"-cn"</CODE> (sort by the <CODE>cn</CODE> attribute in
* reverse order) <P>
* <LI><CODE>"-cn:1.2.3.4"</CODE> (sort by the <CODE>cn</CODE>
* attribute in reverse order and use the matching rule identified
* by the OID 1.2.3.4) <P>
*</UL>
* @see org.ietf.ldap.controls.LDAPSortControl
* @see org.ietf.ldap.controls.LDAPVirtualListControl
*/
public LDAPSortKey( String keyDescription ) {
if ( (keyDescription != null) && (keyDescription.length() > 0) ) {
if ( keyDescription.charAt( 0 ) == '-' ) {
m_reverse = true;
m_key = keyDescription.substring( 1 );
} else {
m_reverse = false;
m_key = keyDescription;
}
int colonIndex = m_key.indexOf( ':' );
if ( colonIndex == 0 )
m_key = null;
else if ( colonIndex > 0 ) {
m_matchRule = m_key.substring( colonIndex+1 );
m_key = m_key.substring( 0, colonIndex );
}
}
}
/**
* Constructs a new <CODE>LDAPSortKey</CODE> object that will
* sort based on the specified attribute and sort order.
* @param key a single attribute by which to sort. For example:
* <P>
* <UL>
* <LI><CODE>"cn"</CODE> (sort by the <CODE>cn</CODE> attribute)
* <LI><CODE>"givenname"</CODE> (sort by the <CODE>givenname</CODE>
* attribute)
* </UL>
* @param reverse if <CODE>true</CODE>, the sorting is done in
* descending order
* @see org.ietf.ldap.controls.LDAPSortControl
* @see org.ietf.ldap.controls.LDAPVirtualListControl
*/
public LDAPSortKey( String key,
boolean reverse) {
m_key = key;
m_reverse = reverse;
m_matchRule = null;
}
/**
* Constructs a new <CODE>LDAPSortKey</CODE> object that will
* sort based on the specified attribute, sort order, and matching
* rule.
* @param key a single attribute by which to sort. For example:
* <P>
* <UL>
* <LI><CODE>"cn"</CODE> (sort by the <CODE>cn</CODE> attribute)
* <LI><CODE>"givenname"</CODE> (sort by the <CODE>givenname</CODE>
* attribute)
* </UL>
* @param reverse if <CODE>true</CODE>, the sorting is done in
* descending order
* @param matchRule object ID (OID) of the matching rule for
* the attribute (for example, <CODE>1.2.3.4</CODE>)
* @see org.ietf.ldap.controls.LDAPSortControl
* @see org.ietf.ldap.controls.LDAPVirtualListControl
*/
public LDAPSortKey( String key,
boolean reverse,
String matchRule) {
m_key = key;
m_reverse = reverse;
m_matchRule = matchRule;
}
/**
* Returns the attribute by which to sort.
* @return a single attribute by which to sort.
*/
public String getKey() {
return m_key;
}
/**
* Returns <CODE>true</CODE> if sorting is to be done in descending order.
* @return <CODE>true</CODE> if sorting is to be done in descending order.
*/
public boolean getReverse() {
return m_reverse;
}
/**
* Returns the object ID (OID) of the matching rule used for sorting.
* If no matching rule is specified, <CODE>null</CODE> is returned.
* @return the object ID (OID) of the matching rule, or <CODE>null</CODE>
* if the sorting instructions specify no matching rule.
*/
public String getMatchRule() {
return m_matchRule;
}
public String toString() {
StringBuffer sb = new StringBuffer("{SortKey:");
sb.append(" key=");
sb.append(m_key);
sb.append(" reverse=");
sb.append(m_reverse);
if (m_matchRule != null) {
sb.append(" matchRule=");
sb.append(m_matchRule);
}
sb.append("}");
return sb.toString();
}
private String m_key;
private boolean m_reverse;
private String m_matchRule;
}

View File

@@ -0,0 +1,182 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
/**
* The definition of a syntax type in the schema.
* <A HREF="http://www.ietf.org/rfc/rfc2252.txt"
* TARGET="_blank">RFC 2252, Lightweight Directory Access Protocol (v3):
* LDAP Subschema Attribute</A> covers the types of information
* to specify when defining a syntax.
* The description of a syntax can include the following:
* <P>
*
* <UL>
* <LI>an OID identifying the syntax
* <LI>a description of the attribute type
* </UL>
* <P>
*
* When you construct an <CODE>LDAPSyntaxSchema</CODE> object, you can
* specify these types of information as arguments to the constructor or
* in the ldapSyntaxes format specified in RFC 2252.
* When an LDAP client searches an LDAP server for the schema, the server
* returns schema information as an object with attribute values in this
* format.
* <P>
* RFC 2252 defines SyntaxDescription as follows:
* <P>
* <PRE>
* SyntaxDescription = "(" whsp
* numericoid whsp
* [ "DESC" qdstring ]
* whsp ")"
* </PRE>
*<P>
* Syntax definitions do not have a name, so the <CODE>getName</CODE>
* method inherited from <CODE>LDAPSchemaElement</CODE> returns "".
* To get the OID and description of this syntax type
* definition, use the <CODE>getOID</CODE> and
* <CODE>getDescription</CODE> methods inherited from the abstract class
* <CODE>LDAPSchemaElement</CODE>.
* <P>
*
* To add or remove this syntax type definition from the
* schema, use the <CODE>add</CODE> and <CODE>remove</CODE>
* methods, which this class inherits from the <CODE>LDAPSchemaElement</CODE>
* abstract class.
*
* @version 1.0
* @see org.ietf.ldap.LDAPSchemaElement
**/
public class LDAPSyntaxSchema extends LDAPSchemaElement {
static final long serialVersionUID = 3590667117475688132L;
/**
* Constructs a blank element.
*/
protected LDAPSyntaxSchema() {
super();
}
/**
* Constructs a syntax type definition, using the specified
* information.
* @param oid object identifier (OID) of the syntax type
* in dotted-string format (for example, "1.2.3.4")
* @param description description of syntax type
*/
public LDAPSyntaxSchema( String oid, String description ) {
super( new String[] { "" }, oid, description );
attrName = "ldapSyntaxes";
syntaxElement.syntax = syntaxElement.syntaxCheck( oid );
syntaxElement.syntaxString = oid;
}
/**
* Constructs a syntax type definition based on a description in
* the ldapSyntaxes format. For information on this format,
* (see <A HREF="http://www.ietf.org/rfc/rfc2252.txt"
* TARGET="_blank">RFC 2252, Lightweight Directory Access Protocol (v3):
* LDAP Subschema Attribute</A>. This is the format that LDAP servers
* and clients use to exchange schema information. (For example, when
* you search an LDAP server for its schema, the server returns an entry
* with the syntaxs "objectclasses" and "ldapSyntaxes". The
* values of "ldapSyntaxes" are syntax type descriptions
* in this format.)
* <P>
*
* @param raw definition of the syntax type in the
* ldapSyntaxes format
*/
public LDAPSyntaxSchema( String raw ) {
attrName = "ldapSyntaxes";
parseValue( raw );
}
/**
* Gets the syntax of the schema element
* @return one of the following values:
* <UL>
* <LI><CODE>cis</CODE> (case-insensitive string)
* <LI><CODE>ces</CODE> (case-exact string)
* <LI><CODE>binary</CODE> (binary data)
* <LI><CODE>int</CODE> (integer)
* <LI><CODE>telephone</CODE> (telephone number -- identical to cis,
* but blanks and dashes are ignored during comparisons)
* <LI><CODE>dn</CODE> (distinguished name)
* <LI><CODE>unknown</CODE> (not a known syntax)
* </UL>
*/
public int getSyntax() {
return syntaxElement.syntax;
}
/**
* Gets the syntax of the syntax type in dotted-decimal format,
* for example "1.2.3.4.5"
* @return The syntax syntax in dotted-decimal format.
*/
public String getSyntaxString() {
return syntaxElement.syntaxString;
}
/**
* Gets the attribute name for a schema element
*
* @return The attribute name of the element
*/
String getAttributeName() {
return "ldapsyntaxes";
}
/**
* Prepares a value in RFC 2252 format for submission to a server
*
* @return a String ready for submission to an LDAP server.
*/
String getValue() {
String s = getValuePrefix();
String val = getCustomValues();
if ( val.length() > 0 ) {
s += val + ' ';
}
s += ')';
return s;
}
/**
* Gets the definition of the syntax in Directory format
*
* @return definition of the syntax in Directory format
*/
public String toString() {
return getValue();
}
protected LDAPSyntaxSchemaElement syntaxElement =
new LDAPSyntaxSchemaElement();
}

View File

@@ -0,0 +1,156 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
/**
* Helper class supporting schema elements that include syntax
* definitions - attributes and matching rules
*
* @version 1.0
* @see org.ietf.ldap.LDAPAttributeSchema
* @see org.ietf.ldap.LDAPMatchingRuleSchema
**/
class LDAPSyntaxSchemaElement extends LDAPSchemaElement {
static final long serialVersionUID = 6086340702503710702L;
/**
* Construct a blank element.
*/
LDAPSyntaxSchemaElement() {
super();
}
/**
* Gets the syntax of the schema element
* @return One of the following values:
* <UL>
* <LI><CODE>cis</CODE> (case-insensitive string)
* <LI><CODE>ces</CODE> (case-exact string)
* <LI><CODE>binary</CODE> (binary data)
* <LI><CODE>int</CODE> (integer)
* <LI><CODE>telephone</CODE> (telephone number -- identical to cis,
* but blanks and dashes are ignored during comparisons)
* <LI><CODE>dn</CODE> (distinguished name)
* <LI><CODE>unknown</CODE> (not a known syntax)
* </UL>
*/
int getSyntax() {
return syntax;
}
/**
* Gets the syntax of the attribute type in dotted-decimal format,
* for example "1.2.3.4.5"
* @return The attribute syntax in dotted-decimal format.
*/
String getSyntaxString() {
return syntaxString;
}
/**
* Convert from enumerated syntax types to an OID
* @param syntax One of the enumerated syntax types
* @return The OID corresponding to the internal type
*/
static String internalSyntaxToString( int syntax ) {
String s;
if ( syntax == cis ) {
s = cisString;
} else if ( syntax == binary ) {
s = binaryString;
} else if ( syntax == ces ) {
s = cesString;
} else if ( syntax == telephone ) {
s = telephoneString;
} else if ( syntax == dn ) {
s = dnString;
} else if ( syntax == integer ) {
s = intString;
} else {
s = null;
}
return s;
}
/**
* Convert from enumerated syntax type to a user-friendly
* string
* @param syntax One of the enumerated syntax types
* @return A user-friendly syntax description
*/
String syntaxToString() {
String s;
if ( syntax == cis ) {
s = "case-insensitive string";
} else if ( syntax == binary ) {
s = "binary";
} else if ( syntax == integer ) {
s = "integer";
} else if ( syntax == ces ) {
s = "case-exact string";
} else if ( syntax == telephone ) {
s = "telephone";
} else if ( syntax == dn ) {
s = "distinguished name";
} else {
s = syntaxString;
}
return s;
}
/**
* Convert from an OID to one of the enumerated syntax types
* @param syntax A dotted-decimal OID
* @return The internal enumerated type corresponding to the
* OID; <CODE>unknown</CODE> if it is not one of the known
* types
*/
int syntaxCheck( String syntax ) {
int i = unknown;
if ( syntax == null ) {
} else if ( syntax.equals( cisString ) ) {
i = cis;
} else if ( syntax.equals( binaryString ) ) {
i = binary;
} else if ( syntax.equals( cesString ) ) {
i = ces;
} else if ( syntax.equals( intString ) ) {
i = integer;
} else if ( syntax.equals( telephoneString ) ) {
i = telephone;
} else if ( syntax.equals( dnString ) ) {
i = dn;
}
return i;
}
public String toString() {
return "LDAPSyntaxSchemaElement: " + getSyntaxString();
}
int syntax = unknown;
String syntaxString = null;
}

View File

@@ -0,0 +1,59 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
/**
* The <CODE>LDAPTraceWriter</CODE> interface enables logging of LDAP
* trace messages in environments where an OutputStream can not be used.
* <P>
* The interface is primarily meant for integrating LDAP tracing with the
* servlet log facility:
* <P>
* <PRE>
* servletCtx = config.getServletContext();
* ...
* LDAPConnection ld = new LDAPConnection();
* ld.setProperty(ld.TRACE_PROPERTY,
* new LDAPTraceWriter() {
* public void write (String msg) {
* servletCtx.log(msg);
* }
* });
* <PRE>
* <P>
*
* @version 1.0
* @see org.ietf.ldap.LDAPConnection#setProperty(java.lang.String, java.lang.Object)
*/
public interface LDAPTraceWriter {
/**
* Writes an LDAP trace message.
*
* @param msg An incoming or outgoing LDAP message
*
* @version 1.0
* @see org.ietf.ldap.LDAPConnection#setProperty(java.lang.String, java.lang.Object)
*/
public void write (String msg);
}

View File

@@ -0,0 +1,38 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
/**
* An object that implements this interface can be notified when
* unsolicited messages arrive from the server. A client registers the
* object with LDAPConnection.addUnsolicitedNotificationListener.
*/
public interface LDAPUnsolicitedNotificationListener {
/**
* The method is called when an unsolicited message arrives from a
* server, if the object has registered with
* LDAPConnection.addUnsolicitedNotificationListener.
*
* @param msg An unsolicited message received from the server
*/
public void messageReceived( LDAPExtendedResponse msg );
}

View File

@@ -0,0 +1,759 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2001 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap;
import java.util.*;
import java.io.*;
import java.net.MalformedURLException;
import org.ietf.ldap.factory.*;
/**
* Represents an LDAP URL. The complete specification for LDAP URLs is in
* <A HREF="http://ds.internic.net/rfc/rfc1959.txt"
* TARGET="_blank">RFC 1959</A>. In addition, the secure ldap (ldaps://) is also
* supported. LDAP URLs have the following format:
*
* <PRE>
* "ldap[s]://" [ <I>hostName</I> [":" <I>portNumber</I>] ] "/"
* <I>distinguishedName</I>
* ["?" <I>attributeList</I> ["?" <I>scope</I>
* "?" <I>filterString</I> ] ]
* </PRE>
* where
* <P>
* <UL>
* <LI>all text within double-quotes are literal<P>
* <LI><CODE><I>hostName</I></CODE> and <CODE><I>portNumber</I></CODE>
* identify the location of the LDAP server.<P>
* <LI><CODE><I>distinguishedName</I></CODE> is the name of an entry
* within the given directory (the entry represents the starting point
* of the search)<P>
* <LI><CODE><I>attributeList</I></CODE> contains a list of attributes
* to retrieve (if null, fetch all attributes). This is a comma-delimited
* list of attribute names.<P>
* <LI><CODE><I>scope</I></CODE> is one of the following:
* <UL>
* <LI><CODE>base</CODE> indicates that this is a search only for the
* specified entry
* <LI><CODE>one</CODE> indicates that this is a search for matching entries
* one level under the specified entry (and not including the entry itself)
* <LI><CODE>sub</CODE> indicates that this is a search for matching entries
* at all levels under the specified entry (including the entry itself)
* </UL>
* <P>
* If not specified, <CODE><I>scope</I></CODE> is <CODE>base</CODE> by
* default. <P>
* <LI><CODE><I>filterString</I></CODE> is a human-readable representation
* of the search criteria. This value is used only for one-level or subtree
* searches.<P>
* </UL>
* <P>
* Note that if <CODE><I>scope</I></CODE> and <CODE><I>filterString</I></CODE>
* are not specified, an LDAP URL identifies exactly one entry in the
* directory. <P>
* The same encoding rules for other URLs (e.g. HTTP) apply for LDAP
* URLs. Specifically, any "illegal" characters are escaped with
* <CODE>%<I>HH</I></CODE>, where <CODE><I>HH</I></CODE> represent the
* two hex digits which correspond to the ASCII value of the character.
* This encoding is only legal (or necessary) on the DN and filter portions
* of the URL.
*
* @version 1.0
*/
public class LDAPUrl implements java.io.Serializable {
static final long serialVersionUID = -3245440798565713640L;
public static String defaultFilter = "(objectClass=*)";
private String _hostName;
private int _portNumber;
private String _DN;
private Vector _attributes;
private int _scope;
private String _filter;
private String _URL;
private boolean _secure;
private String[] _extensions;
private static LDAPSocketFactory _factory;
/**
* The default port number for secure LDAP connections.
* @see org.ietf.ldap.LDAPUrl#LDAPUrl(String, int, String, String[], int,
* String, String[])
*/
public static final int DEFAULT_SECURE_PORT = 636;
/**
* Constructs a URL object with the specified string as URL.
* @param url LDAP search expression in URL form
* @exception MalformedURLException failed to parse URL
*/
public LDAPUrl( String url ) throws java.net.MalformedURLException {
_attributes = null;
_scope = LDAPConnection.SCOPE_BASE;
_filter = defaultFilter;
_URL = url;
parseUrl(url);
}
/**
* Constructs with the specified host, port, and DN. This form is used to
* create URL references to a particular object in the directory.
* @param host host name of the LDAP server, or null for "nearest X.500/LDAP"
* @param port port number of the LDAP server (use LDAPConnection.DEFAULT_PORT for
* the default port)
* @param DN distinguished name of the object
*/
public LDAPUrl( String host,
int port,
String DN ) {
initialize( host, port, DN, null,
LDAPConnection.SCOPE_BASE,
defaultFilter,
null );
}
/**
* Constructs a full-blown LDAP URL to specify an LDAP search operation.
* @param host host name of the LDAP server, or null for "nearest X.500/LDAP"
* @param port port number of the LDAP server (use LDAPConnection.DEFAULT_PORT for
* the default non-secure port or LDAPUrl.DEFAULT_SECURE_PORT for the default
* secure port)
* @param DN distinguished name of the object
* @param attributes list of the attributes to return. Use null for "all
* attributes."
* @param scope depth of the search (in DN namespace). Use one of the LDAPConnection scopes:
* SCOPE_BASE, SCOPE_ONE, or SCOPE_SUB.
* @param filter LDAP filter string (as defined in RFC 1558). Use null for
* no filter (this effectively makes the URL reference a single object).
* @param extensions LDAP URL extensions specified; may be null or
* empty. Each extension is a type=value expression.
* The =value part MAY be omitted. The expression
* may be prefixed with '!' if it is mandatory for
* evaluation of the URL.
*/
public LDAPUrl( String host,
int port,
String DN,
String[] attributes,
int scope,
String filter,
String[] extensions ) {
if ( attributes != null ) {
Vector list = new Vector();
for ( int k = 0; k < attributes.length; k++ ) {
list.addElement(attributes[k]);
}
initialize( host, port, DN, list.elements(), scope, filter,
extensions );
} else {
initialize( host, port, DN, null, scope, filter,
extensions );
}
}
/**
* Decodes a URL-encoded string. Any occurences of %HH are decoded to the
* hex value represented. However, this routine does NOT decode "+"
* into " ". See RFC 1738 for full details about URL encoding/decoding.
* @param URLEncoded a segment of a URL which was encoded using the URL
* encoding rules
* @exception MalformedURLException failed to parse URL
*/
public static String decode( String URLEncoded )
throws MalformedURLException {
StringBuffer decoded = new StringBuffer (URLEncoded);
int srcPos = 0, dstPos = 0;
try {
while (srcPos < decoded.length()) {
if (decoded.charAt (srcPos) != '%') {
if (srcPos != dstPos)
decoded.setCharAt (dstPos, decoded.charAt (srcPos));
srcPos++;
dstPos++;
continue;
}
decoded.setCharAt (dstPos, (char)
((hexValue(decoded.charAt (srcPos+1))<<4) |
(hexValue(decoded.charAt (srcPos+2)))));
dstPos++;
srcPos += 3;
}
} catch (StringIndexOutOfBoundsException sioob) {
// Indicates that a "%" character occured without the following HH
throw new MalformedURLException ();
}
/* 070497 Url problems submitted by Netscape */
/* decoded.setLength (dstPos+1); */
decoded.setLength (dstPos);
return decoded.toString ();
}
/**
* Encodes an arbitrary string. Any illegal characters are encoded as
* %HH. However, this routine does NOT decode "+" into " " (this is a HTTP
* thing, not a general URL thing). Note that, because Sun's URLEncoder
* does do this encoding, we can't use it.
* See RFC 1738 for full details about URL encoding/decoding.
* @param toEncode an arbitrary string to encode for embedding within a URL
*/
public static String encode( String toEncode ) {
StringBuffer encoded = new StringBuffer (toEncode.length()+10);
for (int currPos = 0; currPos < toEncode.length(); currPos++) {
char currChar = toEncode.charAt (currPos);
if ((currChar >= 'a' && currChar <= 'z') ||
(currChar >= 'A' && currChar <= 'Z') ||
(currChar >= '0' && currChar <= '9') ||
("$-_.+!*'(),".indexOf (currChar) > 0)) {
// this is the criteria for "doesn't need to be encoded" (whew!)
encoded.append (currChar);
} else {
encoded.append ("%");
encoded.append (hexChar ((currChar & 0xF0) >> 4));
encoded.append (hexChar (currChar & 0x0F));
}
}
return encoded.toString();
}
/**
* Return the collection of attributes specified in the URL, or null
* for "every attribute"
* @return string array of attributes.
*/
public String[] getAttributeArray() {
if ( _attributes == null ) {
return new String[0];
} else {
String[] attrNames = new String[_attributes.size()];
Enumeration attrs = getAttributes();
int i = 0;
while ( attrs.hasMoreElements() ) {
attrNames[i++] = (String)attrs.nextElement();
}
return attrNames;
}
}
/**
* Return the collection of attributes specified in the URL, or null
* for "every attribute"
* @return enumeration of attributes.
*/
public Enumeration getAttributes() {
if ( _attributes == null ) {
return null;
} else {
return _attributes.elements();
}
}
/**
* Return the distinguished name encapsulated in the URL
* @return target distinguished name.
*/
public String getDN() {
return _DN;
}
/**
* Returns the search filter (RFC 1558), or the default if none was
* specified.
* @return the search filter.
*/
public String getFilter() {
return _filter;
}
/**
* Return the host name of the LDAP server
* @return LDAP host.
*/
public String getHost() {
return _hostName;
}
/**
* Return the port number for the LDAP server
* @return port number.
*/
public int getPort() {
return _portNumber;
}
/**
* Returns the scope of the search, according to the values
* SCOPE_BASE, SCOPE_ONE, SCOPE_SUB as defined in LDAPConnection. This refers
* to how deep within the directory namespace the search will look
* @return search scope.
*/
public int getScope() {
return _scope;
}
/**
* Returns the scope of the search. If the scope returned is -1, then
* the given string is not for the scope.
* @param str the string against which to compare the scope type
* @returns the scope of the search, -1 is returned if the given string is
* not SUB, ONE or BASE (the acceptable LDAPConnection values for scope).
*/
private int getScope(String str) {
int s = -1;
if (str.equalsIgnoreCase("base"))
s = LDAPConnection.SCOPE_BASE;
else if (str.equalsIgnoreCase("one"))
s = LDAPConnection.SCOPE_ONE;
else if (str.equalsIgnoreCase("sub"))
s = LDAPConnection.SCOPE_SUB;
return s;
}
/**
* Gets the socket factory to be used for ldaps:// URLs.
* <P>
* If the factory is not explicitly specified with
* <CODE>LDAPUrl.setSocketFactory</CODE>, the method will
* attempt the determine the default factory based on the
* available factories in the org.ietf.ldap.factory package.
*
* @return the socket factory to be used for ldaps:// URLs
*/
public static LDAPSocketFactory getSocketFactory() {
if (_factory == null) {
// No factory explicity set, try to determine
// the default one.
try {
// First try iPlanet JSSSocketFactory
Class c = Class.forName("org.ietf.ldap.factory.JSSSocketFactory");
_factory = (LDAPSocketFactory) c.newInstance();
}
catch (Throwable e) {
}
if (_factory != null) {
return _factory;
}
try {
// then try Sun JSSESocketFactory
_factory = new JSSESocketFactory(null);
}
catch (Throwable e) {
}
}
return _factory;
}
/**
* Returns true if the secure ldap protocol is used.
* @return true if ldaps is used.
*/
public boolean isSecure() {
return _secure;
}
/**
* Sets the socket factory to be used for ldaps:// URLs.
* Overrides the default factory assigned by the LDAPUrl
* class.
* @param the socket factory to be used for ldaps:// URLs
* @see org.ietf.ldap.LDAPUrl#getSocketFactory
*/
public static void setSocketFactory( LDAPSocketFactory factory ) {
_factory = factory;
}
/**
* Sets the protocol to ldaps or ldap
*
* @param secure <CODE>true</CODE> for ldaps
*/
public void setSecure( boolean secure ) {
_secure = secure;
initialize( _hostName, _portNumber, _DN, getAttributes(), _scope,
_filter, _extensions );
}
/**
* Returns the URL in String format
*
* @return the URL in String format
*/
public String toString() {
return _URL;
}
/**
* Parse URL as defined in RFC 1959. Beyond the RFC, the secure ldap
* (ldaps) is also supported.
*/
private void parseUrl(String url) throws MalformedURLException {
StringTokenizer urlParser = new StringTokenizer (url, ":/?", true);
String currentToken;
String str = null;
try {
currentToken = urlParser.nextToken();
if (currentToken.equalsIgnoreCase ("LDAPS")) {
_secure = true;
}
else if (!currentToken.equalsIgnoreCase ("LDAP")) {
throw new MalformedURLException ();
}
currentToken = urlParser.nextToken();
if (!currentToken.equals(":")) {
throw new MalformedURLException ();
}
currentToken = urlParser.nextToken();
if (!currentToken.equals("/")) {
throw new MalformedURLException ();
}
currentToken = urlParser.nextToken();
if (!currentToken.equals("/")) {
throw new MalformedURLException ();
}
currentToken = urlParser.nextToken();
}
catch (NoSuchElementException e) {
throw new MalformedURLException ();
}
// host-port
if (currentToken.equals ("/")) {
_hostName = null;
_portNumber = _secure ? DEFAULT_SECURE_PORT : LDAPConnection.DEFAULT_PORT;
} else if (currentToken.equals (":")) {
// port number without host name is not allowed
throw new MalformedURLException ("No hostname");
} else if (currentToken.equals ("?")) {
throw new MalformedURLException ("No host[:port]");
} else {
_hostName = currentToken;
if (urlParser.countTokens() == 0) {
_portNumber = _secure ? DEFAULT_SECURE_PORT : LDAPConnection.DEFAULT_PORT;
return;
}
currentToken = urlParser.nextToken (); // either ":" or "/"
if (currentToken.equals (":")) {
try {
_portNumber = Integer.parseInt (urlParser.nextToken());
} catch (NumberFormatException nf) {
throw new MalformedURLException ("Port not a number");
} catch (NoSuchElementException ex) {
throw new MalformedURLException ("No port number");
}
if (urlParser.countTokens() == 0) {
return;
}
else if (! urlParser.nextToken().equals("/")) {
throw new MalformedURLException ();
}
} else if (currentToken.equals ("/")) {
_portNumber = _secure ? DEFAULT_SECURE_PORT : LDAPConnection.DEFAULT_PORT;
} else {
// expecting ":" or "/"
throw new MalformedURLException ();
}
}
// DN
if (!urlParser.hasMoreTokens ()) {
return;
}
_DN = decode(readNextConstruct(urlParser));
if (_DN.equals("?")) {
_DN = "";
}
else if (_DN.equals("/")) {
throw new MalformedURLException ();
}
// attribute
if (!urlParser.hasMoreTokens ()) {
return;
}
str = readNextConstruct(urlParser);
if (!str.equals("?")) {
StringTokenizer attributeParser = new
StringTokenizer (decode(str), ", ");
_attributes = new Vector ();
while (attributeParser.hasMoreTokens()) {
_attributes.addElement (attributeParser.nextToken());
}
}
// scope
if (!urlParser.hasMoreTokens ()) {
return;
}
str = readNextConstruct(urlParser);
if (!str.equals("?")) {
_scope = getScope(str);
if (_scope < 0) {
throw new MalformedURLException("Bad scope:" + str);
}
}
// filter
if (!urlParser.hasMoreTokens ()) {
return;
}
str = readNextConstruct(urlParser);
_filter = decode(str);
checkBalancedParentheses(_filter);
if (!_filter.startsWith("(") && !_filter.endsWith(")")) {
_filter = "(" + _filter + ")";
}
// Nothing after the filter is allowed
if (urlParser.hasMoreTokens()) {
throw new MalformedURLException();
}
}
private void checkBalancedParentheses( String filter )
throws MalformedURLException {
int parenCnt =0;
StringTokenizer filterParser =
new StringTokenizer (filter, "()", true);
while (filterParser.hasMoreElements()) {
String token = filterParser.nextToken();
if (token.equals("(")) {
parenCnt++;
}
else if (token.equals(")")) {
if (--parenCnt < 0) {
throw new MalformedURLException(
"Unbalanced filter parentheses");
}
}
}
if (parenCnt != 0) {
throw new MalformedURLException("Unbalanced filter parentheses");
}
}
/**
* Initializes URL object.
*/
private void initialize( String host,
int port,
String DN,
Enumeration attributes,
int scope,
String filter,
String[] extensions ) {
_hostName = host;
_DN = DN;
_portNumber = port;
_filter = (filter != null) ? filter : defaultFilter;
_scope = scope;
_extensions = extensions;
if (attributes != null) {
_attributes = new Vector ();
while (attributes.hasMoreElements()) {
_attributes.addElement (attributes.nextElement());
}
} else
_attributes = null;
StringBuffer url = new StringBuffer (_secure ? "LDAPS://" :"LDAP://");
if (host != null) {
url.append (host);
url.append (':');
url.append (String.valueOf (port));
}
url.append ('/');
url.append (encode (DN));
if (attributes != null) {
url.append ('?');
Enumeration attrList = _attributes.elements();
boolean firstElement = true;
while (attrList.hasMoreElements()) {
if (!firstElement)
url.append (',');
else
firstElement = false;
url.append ((String)attrList.nextElement());
}
}
if (filter != null) {
if (attributes == null)
url.append ('?');
url.append ('?');
switch (scope) {
default:
case LDAPConnection.SCOPE_BASE:
url.append ("base"); break;
case LDAPConnection.SCOPE_ONE:
url.append ("one"); break;
case LDAPConnection.SCOPE_SUB:
url.append ("sub"); break;
}
url.append ('?');
url.append (filter);
}
_URL = url.toString();
}
/**
* Reads next construct from the given string parser.
* @param parser the string parser
* @return the next construct which can be an attribute, scope or filter.
* @exception java.net.MalformedURLException Get thrown when the url format
* is incorrect.
*/
private String readNextConstruct(StringTokenizer parser) throws
MalformedURLException {
try {
if (parser.hasMoreTokens()) {
String tkn = parser.nextToken();
if (tkn.equals("?")) { // empty construct
return tkn;
}
else if (parser.hasMoreTokens()){
// Remove '?' delimiter
String delim = parser.nextToken();
if (!delim.equals("?")) {
throw new MalformedURLException();
}
}
return tkn;
}
} catch (NoSuchElementException e) {
throw new MalformedURLException();
}
return null;
}
/**
* Parses hex character into integer.
*/
private static int hexValue (char hexChar) throws MalformedURLException {
if (hexChar >= '0' && hexChar <= '9')
return hexChar - '0';
if (hexChar >= 'A' && hexChar <= 'F')
return hexChar - 'A' + 10;
if (hexChar >= 'a' && hexChar <= 'f')
return hexChar - 'a' + 10;
throw new MalformedURLException ();
}
private static char hexChar (int hexValue) {
if (hexValue < 0 || hexValue > 0xF)
return 'x';
if (hexValue < 10)
return (char)(hexValue + '0');
return (char)((hexValue - 10) + 'a');
}
/**
* Reports if the two objects represent the same URL
*
* @param url the object to be compared to
* @return <CODE>true</CODE> if the two are equivalent
*/
public boolean equals( LDAPUrl url ) {
if ( getHost() == null ) {
if ( url.getHost() != null ) {
return false;
}
} else if ( !getHost().equals( url.getHost() ) ) {
return false;
}
if ( getPort() != url.getPort() ) {
return false;
}
if ( getDN() == null ) {
if ( url.getDN() != null ) {
return false;
}
} else if ( !getDN().equals( url.getDN() ) ) {
return false;
}
if ( getFilter() == null ) {
if ( url.getFilter() != null ) {
return false;
}
} else if ( !getFilter().equals( url.getFilter() ) ) {
return false;
}
if ( getScope() != url.getScope() ) {
return false;
}
if ( _attributes == null ) {
if ( url._attributes != null ) {
return false;
}
} else if ( _attributes.size() != url._attributes.size() ) {
return false;
} else {
for( int i = 0; i < _attributes.size(); i++ ) {
if ( _attributes.elementAt( i ) !=
url._attributes.elementAt( i ) ) {
return false;
}
}
}
return true;
}
}

View File

@@ -0,0 +1,92 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This class is for the "any" object that is unknown to the
* BER package but conforms to BER rules.
* <P>See CCITT X.209.
*
*
* <pre>
* Encoding Rule:
* The encoding is that of the particular implementation.
* </pre>
*
* @version 1.0
*/
public class BERAny extends BERElement {
/**
* Internal variables
*/
private BERElement m_value = null;
/**
* Constructs an "any" element.
* @param value BERElement value
*/
public BERAny(BERElement value) {
m_value = value;
}
/**
* Constructs an "any" element from an input stream.
* Note that with the current decoding architecture "any" types
* will not be decoded as any's but rather as the particular
* implementation. The following method will never be called.
* @param stream input stream
* @param bytes_read array of 1 int; value incremented by
* number of bytes read from stream
* @exception IOException failed to construct
*/
public BERAny(BERTagDecoder decoder, InputStream stream,
int[] bytes_read) throws IOException {
m_value = getElement(decoder, stream, bytes_read);
}
/**
* Sends the BER encoding directly to an output stream.
* @param stream output stream
*/
public void write(OutputStream stream) throws IOException {
m_value.write(stream);
}
/**
* Gets the element type.
* @param element type
*/
public int getType() {
return BERElement.ANY;
}
/**
* Gets the string representation.
* @return string representation of tag.
*/
public String toString() {
return "ANY {" + m_value + "}";
}
}

View File

@@ -0,0 +1,284 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.util.BitSet;
import java.io.*;
/**
* This class is for the BitString object. Note that the BitSet class
* has a bug: size() returns the size of the internal allocated memory
* rather than the number of bits. Current work-around is to maintain
* the number of bits ourselves in m_value_num_bits.
* Change is required when BitSet is fixed.
* <P>See CCITT X.209.
*
*
* <pre>
* ENCODING RULE:
* Primitive Definite length.
* tag = 0x03
* </pre>
*
* @version 1.0
*/
public class BERBitString extends BERElement {
/**
* Internal variables
*/
private BitSet m_value;
private int m_value_num_bits;
/**
* Constructs a boolean element.
* @param value boolean value
*/
public BERBitString(BitSet value) {
m_value = value;
}
/**
* Constructs a bitstring element from an input stream
* (for constructed encodings).
* @param stream source
* @param bytes_read array of 1 int; value incremented by
* number of bytes read from stream
* @exception IOException failed to construct
*/
public BERBitString(BERTagDecoder decoder, InputStream stream,
int[] bytes_read) throws IOException {
int octet;
int contents_length = super.readLengthOctets(stream, bytes_read);
int[] component_length = new int[1];
BERElement element = null;
if (contents_length == -1) {
/* Constructed - indefinite length. */
{
component_length[0] = 0;
element = getElement(decoder,stream,component_length);
if (element != null) {
/* element is a bitstring - add it to the existing BitSet */
BERBitString bit_string_element = (BERBitString)element;
BitSet new_bit_set = new BitSet(m_value_num_bits +
bit_string_element.getSize());
for (int i = 0; i<m_value_num_bits; i++)
if (m_value.get(i))
new_bit_set.set(i);
for (int j = 0; j<bit_string_element.getSize(); j++)
if (bit_string_element.getValue().get(j))
new_bit_set.set(m_value_num_bits+j);
m_value = new_bit_set;
m_value_num_bits += bit_string_element.getSize();
}
} while (element != null);
} else {
/* Constructed - definite length */
bytes_read[0] += contents_length;
while (contents_length > 0) {
component_length[0] = 0;
element = getElement(decoder,stream,component_length);
if (element != null) {
/* element is a bitstring - add it to the existing BitSet */
BERBitString bit_string_element = (BERBitString)element;
BitSet new_bit_set = new BitSet(m_value_num_bits +
bit_string_element.getSize());
for (int i = 0; i<m_value_num_bits; i++)
if (m_value.get(i))
new_bit_set.set(i);
for (int j = 0; j<bit_string_element.getSize(); j++)
if (bit_string_element.getValue().get(j))
new_bit_set.set(m_value_num_bits+j);
m_value = new_bit_set;
m_value_num_bits += bit_string_element.getSize();
}
contents_length -= component_length[0];
}
}
}
/**
* Constructs a bitstring element from an input stream
* (for primitive encodings).
* @param stream source
* @param bytes_read array of 1 int; value incremented by
* number of bytes read from stream
* @exception IOException failed to construct
*/
public BERBitString(InputStream stream, int[] bytes_read)
throws IOException {
/* Primitive - definite length content octets string. */
int octet;
int contents_length = super.readLengthOctets(stream, bytes_read);
/* First content octect doesn't encode any of
* the string - it encodes the number of unused
* bits in the final content octet.
*/
int last_unused_bits = stream.read();
bytes_read[0]++;
contents_length--;
m_value_num_bits = ((contents_length-1)*8) + (8-last_unused_bits);
m_value = new BitSet();
int bit_num = 0;
for (int i = 0; i < contents_length-1; i++) {
octet = stream.read();
int mask = 0x80;
for (int j = 0; j < 8; j++) {
if ((octet & mask) > 0) {
m_value.set(bit_num);
}
else
m_value.clear(bit_num);
bit_num++;
mask = mask / 2;
}
}
octet = stream.read(); /* last content octet */
int mask = 0x80;
for (int j = 0; j < 8-last_unused_bits; j++) {
if ((octet & mask) > 0)
m_value.set(bit_num);
else
m_value.clear(bit_num);
bit_num++;
mask = mask / 2;
}
bytes_read[0] += contents_length;
}
/**
* Sends the BER encoding directly to a stream.
* Always sends in primitive form.
* @param stream output stream
*/
public void write(OutputStream stream) throws IOException {
stream.write(BERElement.BITSTRING);
//int num_bits = m_value.size(); /* number of bits to send */
int num_bits = m_value_num_bits;
/* Number of bits unused int the last contents octet */
int last_unused_bits = 8 - (num_bits % 8);
/* Figure out the number of content octets */
int num_content_octets = (int)(num_bits/8) + 1;
if (last_unused_bits > 0)
num_content_octets += 1;
stream.write(num_content_octets); /* length octet */
stream.write(last_unused_bits); /* first content octet */
for (int i = 0; i < (int)(num_bits/8); i++) {
int new_octet = 0;
int bit = 0x80;
for (int j = 0; j < 8; j++) {
if (m_value.get(i*8+j))
new_octet += bit;
bit = bit/2;
}
stream.write(new_octet);
}
/*
* Last octet may not use all bits. If last octet DOES use all
* bits then it has already been written above.
*/
if (last_unused_bits > 0) {
int new_octet = 0;
int bit = 0x80;
for (int j = 0; j < last_unused_bits; j++) {
if (m_value.get(((int)(num_bits/8))*8+j))
new_octet += bit;
bit = bit/2;
}
stream.write(new_octet);
}
}
/**
* Gets the bitstring value.
* @param element type
*/
public BitSet getValue() {
return m_value;
}
/**
* Gets the number of bits.
* @return bit numbers.
*/
public int getSize() {
return m_value_num_bits;
}
/**
* Gets the element type.
* @param element type
*/
public int getType() {
return BERElement.BITSTRING;
}
/**
* Gets the string representation.
* @return string representation of tag.
*/
public String toString() {
String hex_string = "";
int octet;
//int num_bits = m_value.size();
int num_bits = m_value_num_bits;
for (int i = 0; i < (int)(num_bits/8); i++) {
octet = 0;
int bit = 0x80;
for (int j = 0; j < 8; j++) {
if (m_value.get(i*8+j))
octet += bit;
bit = bit/2;
}
hex_string += " " + (byte)octet;
}
int bit = 0x80;
octet = 0;
for (int k = 0; k < num_bits-(int)(num_bits/8); k++) {
if (m_value.get(((int)(num_bits/8))*8+k))
octet += bit;
bit = bit/2;
}
hex_string += " " + (byte)octet;
return "Bitstring {" + hex_string + " }";
}
}

View File

@@ -0,0 +1,114 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This class is for the Boolean object.
* <P>See CCITT X.209.
*
* <pre>
* ENCODING RULE:
* tag = 0x01
* length = 0x01
* one contents octet (non-zero indicates TRUE).
*
* Example 1: (false)
* 01 01 00
* Example 2: (true)
* 01 01 FF
* </pre>
*
* @version 1.0
*/
public class BERBoolean extends BERElement {
/**
* Internal variables
*/
private boolean m_value = true;
/**
* Constructs a boolean element.
* @param value boolean value
*/
public BERBoolean(boolean value) {
m_value = value;
}
/**
* Constructs a boolean element from an input stream.
* @param stream source
* @param bytes_read array of 1 int; value incremented by
* number of bytes read from stream
* @exception IOException failed to construct
*/
public BERBoolean(InputStream stream, int[] bytes_read) throws IOException {
int octet = stream.read(); /* skip length */
bytes_read[0]++;
octet = stream.read(); /* content octet */
bytes_read[0]++;
if (octet > 0)
m_value = true;
else
m_value = false;
}
/**
* Sends the BER encoding directly to a stream.
* @param stream output stream
*/
public void write(OutputStream stream) throws IOException {
stream.write(BERElement.BOOLEAN);
stream.write(0x01);
if (m_value)
stream.write(0xFF); /* non-zero means true. */
else
stream.write(0x00); /* zero means false. */
}
/**
* Gets the boolean value.
* @param element type
*/
public boolean getValue() {
return m_value;
}
/**
* Gets the element type.
* @param element type
*/
public int getType() {
return BERElement.BOOLEAN;
}
/**
* Gets the string representation.
* @return string representation of tag.
*/
public String toString() {
return "Boolean {" + m_value + "}";
}
}

View File

@@ -0,0 +1,180 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This is an abstract base class for character string types.
*
* @version 1.0
*/
public abstract class BERCharacterString extends BERElement {
/**
* Internal variables
*/
protected String m_value = null;
/**
* Constructs a character string element containing a buffer.
*/
public BERCharacterString() {
}
/**
* Constructs a character string element containing buffer.
* @param buffer a string value
*/
public BERCharacterString(String string) {
m_value = string;
}
/**
* Constructs a character string element from a byte array.
* @param buffer buffer containing UTF8 data
*/
public BERCharacterString(byte[] buffer) {
try{
m_value = new String(buffer,"UTF8");
} catch(Throwable x)
{}
}
/**
* Constructs a character string element from an input stream
* (for constructed encoding)
* @param stream input stream
* @param bytes_read array of 1 int, incremented by number of bytes read
* @exception IOException failed to construct
*/
public BERCharacterString(BERTagDecoder decoder, InputStream stream,
int[] bytes_read) throws IOException {
int octet;
int contents_length = super.readLengthOctets(stream, bytes_read);
int[] component_length = new int[1];
BERElement element = null;
if (contents_length == -1) {
/* Constructed - indefinite length content octets. */
do {
component_length[0] = 0;
element = getElement(decoder,stream,component_length);
if (element != null) {
/* element is a string of same type
* - add it to the existing buffer */
BERCharacterString octet_element = (BERCharacterString)element;
String string_buffer = octet_element.getValue();
if (m_value == null) {
m_value = string_buffer;
} else {
m_value = m_value + string_buffer;
}
}
} while (element != null);
} else {
/* Definite length content octets string. */
bytes_read[0] += contents_length;
while (contents_length > 0) {
component_length[0] = 0;
element = getElement(decoder,stream,component_length);
if (element != null) {
/* element is a string of the same type
* - add it to the existing buffer */
BERCharacterString octet_element = (BERCharacterString)element;
String string_buffer = octet_element.getValue();
if (m_value == null) {
m_value = string_buffer;
} else {
m_value = m_value + string_buffer;
}
}
contents_length -= component_length[0];
}
}
}
/**
* Constructs a character string element from an input stream
* (for primitive encoding)
* @param stream source
* @param bytes_read array of 1 int, incremented by number of bytes read
* @exception IOException failed to construct
*/
public BERCharacterString(InputStream stream, int[] bytes_read)
throws IOException {
int contents_length = super.readLengthOctets(stream, bytes_read);
/* Definite length content octets string. */
if (contents_length > 0) {
byte[] buffer = new byte[contents_length];
for (int i = 0; i < contents_length; i++) {
buffer[i] = (byte) stream.read();
}
bytes_read[0] += contents_length;
try {
m_value = new String(buffer,"UTF8");
} catch(Throwable x)
{}
}
}
private byte[] byte_buf;
/**
* Writes BER to stream.
* @param stream output stream
*/
public void write(OutputStream stream) throws IOException {
stream.write(getType()); /* tag */
if (m_value == null) {
sendDefiniteLength(stream, 0);
} else {
try {
byte_buf = m_value.getBytes("UTF8");
sendDefiniteLength(stream, byte_buf.length); /* length */
} catch(Throwable x)
{}
stream.write(byte_buf,0,byte_buf.length); /* contents */
}
}
/**
* Gets the element value.
* @param element value
*/
public String getValue() {
return m_value;
}
/**
* Gets the element type.
* @param element type
*/
public abstract int getType();
/**
* Gets the string representation.
* @return string representation.
*/
public abstract String toString();
}

View File

@@ -0,0 +1,100 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This class is for the Choice object. Note that this class may be
* used by a client.
* <P>See CCITT X.209.
*
* <pre>
* ENCODING RULE:
* Encoding is the encoding of the specific type used.
* </pre>
*
* @version 1.0
*/
public class BERChoice extends BERElement {
/**
* Internal variables
*/
private BERElement m_value = null;
/**
* Constructs a choice element.
* @param value any BERElement value
*/
public BERChoice(BERElement value) {
m_value = value;
}
/**
* Constructs a choice element from an input stream.
* Note that with the current decoding architecture choice types
* will not be decoded as choices but rather as the types
* chosen. The following method will never be called.
* @param stream input stream
* @param bytes_read array of 1 int; value incremented by
* number of bytes read from stream
* @exception IOException failed to construct
*/
public BERChoice(BERTagDecoder decoder, InputStream stream,
int[] bytes_read) throws IOException {
m_value = getElement(decoder, stream, bytes_read);
}
/**
* Sends the BER encoding of the chosen type directly to a stream.
* @param stream output stream
* @exception IOException failed to write
*/
public void write(OutputStream stream) throws IOException {
m_value.write(stream);
}
/**
* Gets the value of the chosen type.
* @param element type
*/
public BERElement getValue() {
return m_value;
}
/**
* Gets the element type.
* @param element type
*/
public int getType() {
return BERElement.CHOICE;
}
/**
* Gets the string representation.
* @return string representation of tag.
*/
public String toString() {
return "CHOICE {" + m_value + "}";
}
}

View File

@@ -0,0 +1,134 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This abstract class serves as a base class for constructed
* types such as sequence or set.
* <P>See CCITT X.209.
*
* @version 1.0
*/
public abstract class BERConstruct extends BERElement {
/**
* List of BER elements in the construct.
*/
private Vector m_elements = new Vector();
/**
* Constructs a construct element.
*/
public BERConstruct() {
}
/**
* Constructs a construct element from an input stream.
* @param decoder decoder for application specific BER
* @param stream input stream from socket
* @param bytes_read array of 1 int; value incremented by number
* of bytes read from stream
* @exception IOException failed to construct
*/
public BERConstruct(BERTagDecoder decoder, InputStream stream,
int[] bytes_read) throws IOException {
int contents_length = super.readLengthOctets(stream,bytes_read);
int[] component_length = new int[1];
if (contents_length == -1) {
/* Constructed - indefinite length */
BERElement element = null;
{
component_length[0] = 0;
element = getElement(decoder, stream, component_length);
if (element != null)
addElement(element);
} while (element != null);
} else {
/* Constructed - definite length */
bytes_read[0] += contents_length;
while (contents_length > 0)
{
component_length[0] = 0;
addElement(getElement(decoder, stream,component_length));
contents_length -= component_length[0];
}
}
}
/**
* Adds an element to the list.
* @return BER encoding of the element.
*/
public void addElement(BERElement element) {
m_elements.addElement(element);
}
/**
* Retrieves number of elements.
* @return number of elements.
*/
public int size() {
return m_elements.size();
}
/**
* Gets ber element at specific position.
* @param index index of the element to get
* @return BER element.
*/
public BERElement elementAt(int index) {
return (BERElement)m_elements.elementAt(index);
}
/**
* Sends the BER encoding directly to a stream.
* @param stream output stream
* @exception IOException failed to send
*/
public void write(OutputStream stream) throws IOException {
stream.write(getType());
ByteArrayOutputStream contents_stream = new ByteArrayOutputStream();
for (int i = 0; i < m_elements.size(); i++) {
BERElement e = elementAt(i);
e.write(contents_stream);
}
byte[] contents_buffer = contents_stream.toByteArray();
sendDefiniteLength(stream, contents_buffer.length);
stream.write(contents_buffer);
}
/**
* Gets the element type.
* @param element type
*/
public abstract int getType();
/**
* Gets the string representation.
* @return string representation of tag.
*/
public abstract String toString();
}

View File

@@ -0,0 +1,322 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This class is for the tagged object type. A nested tag is
* allowed. A tagged element contains another BER element.
* <P>See CCITT X.209.
*
* @version 1.0
*/
public abstract class BERElement implements Serializable {
/**
* Possible element types.
*/
public final static int BOOLEAN = 0x01;
public final static int INTEGER = 0x02;
public final static int BITSTRING = 0x03;
public final static int OCTETSTRING = 0x04;
public final static int NULL = 0x05;
public final static int OBJECTID = 0x06;
public final static int REAL = 0x09;
public final static int ENUMERATED = 0x0a;
public final static int SET = 0x31; /* always constructed */
public final static int SEQUENCE = 0x30; /* always constructed */
public final static int NUMERICSTRING = 0x12;
public final static int PRINTABLESTRING = 0x13;
public final static int TELETEXSTRING = 0x14;
public final static int VIDEOTEXSTRING = 0x15;
public final static int IA5STRING = 0x16;
public final static int UTCTIME = 0x17;
public final static int GRAPHICSTRING = 0x19;
public final static int VISIBLESTRING = 0x1A;
public final static int GENERALSTRING = 0x1B;
/**
* Internal (non-transmitted) tags.
*/
public final static int TAG = -1;
public final static int CHOICE = -2;
public final static int ANY = -3;
/**
* Possible tags.
*/
public final static int EOC = 0x00; /* End Of Construction */
public final static int UNIVERSAL = 0x00;
public final static int APPLICATION = 0x40;
public final static int CONTEXT = 0x80;
public final static int SASLCONTEXT = 0xa0;
public final static int PRIVATE = 0xC0;
public final static int PRIMITIVE = 0x00;
public final static int CONSTRUCTED = 0x20;
public final static int MRA_OID = 0x01;
public final static int MRA_TYPE = 0x02;
public final static int MRA_VALUE = 0x03;
public final static int MRA_DNATTRS = 0x04;
public final static int EXOP_REQ_OID = 0x00;
public final static int EXOP_REQ_VALUE = 0x01;
public final static int EXOP_RES_OID = 0x0a;
public final static int EXOP_RES_VALUE = 0x0b;
public final static int SK_MATCHRULE = 0x00;
public final static int SK_REVERSE = 0x01;
public final static int SR_ATTRTYPE = 0x00;
/**
* Gets a ber element from the input stream.
* @param decoder decoder for application specific BER
* @param stream source of ber encoding
* @param bytes_read array of 1 int; value incremented by
* number of bytes read from stream
* @exception IOException failed to decode an element.
*/
public static BERElement getElement(BERTagDecoder decoder,
InputStream stream, int[] bytes_read) throws IOException {
BERElement element = null;
int tag = stream.read();
bytes_read[0] = 1;
if (tag == EOC) {
stream.read(); /* length octet (always zero) */
bytes_read[0] = 1;
element = null;
} else if (tag == BOOLEAN) {
element = new BERBoolean(stream, bytes_read);
} else if (tag == INTEGER) {
element = new BERInteger(stream, bytes_read);
} else if (tag == BITSTRING) {
element = new BERBitString(stream, bytes_read);
} else if (tag == (BITSTRING | CONSTRUCTED)) {
element = new BERBitString(decoder, stream, bytes_read);
} else if (tag == OCTETSTRING) {
element = new BEROctetString(stream, bytes_read);
} else if (tag == (OCTETSTRING | CONSTRUCTED)) {
element = new BEROctetString(decoder, stream, bytes_read);
} else if (tag == NULL) {
element = new BERNull(stream, bytes_read);
} else if (tag == OBJECTID) {
element = new BERObjectId(stream, bytes_read);
} else if (tag == REAL) {
element = new BERReal(stream, bytes_read);
} else if (tag == ENUMERATED) {
element = new BEREnumerated(stream, bytes_read);
} else if (tag == SEQUENCE) {
element = new BERSequence(decoder, stream, bytes_read);
} else if (tag == SET) {
element = new BERSet(decoder, stream, bytes_read);
} else if (tag == NUMERICSTRING) {
element = new BERNumericString(stream, bytes_read);
} else if (tag == (NUMERICSTRING | CONSTRUCTED)) {
element = new BERNumericString(decoder, stream, bytes_read);
} else if (tag == PRINTABLESTRING) {
element = new BERPrintableString(stream, bytes_read);
} else if (tag == (PRINTABLESTRING | CONSTRUCTED)) {
element = new BERPrintableString(decoder, stream, bytes_read);
} else if (tag == UTCTIME) {
element = new BERUTCTime(stream, bytes_read);
} else if (tag == (UTCTIME | CONSTRUCTED)) {
element = new BERUTCTime(decoder, stream, bytes_read);
} else if (tag == VISIBLESTRING) {
element = new BERVisibleString(stream, bytes_read);
} else if (tag == (VISIBLESTRING | CONSTRUCTED)) {
element = new BERVisibleString(decoder, stream, bytes_read);
} else if ((tag & (APPLICATION | PRIVATE | CONTEXT)) > 0) {
element = new BERTag(decoder, tag, stream, bytes_read);
} else
throw new IOException("invalid tag " + tag);
return element;
}
/**
* Reads and decodes a length byte and then that many octets
* from the input stream.
* @param stream input stream from which to read
* @param bytes_read array of 1 int; value incremented by
* number of bytes read from stream
* @return length of contents or -1 if indefinite length.
* @exception IOException failed to read octets
*/
public static int readLengthOctets(InputStream stream, int[] bytes_read)
throws IOException {
int contents_length = 0;
int octet = stream.read();
bytes_read[0]++;
if (octet == 0x80)
/* Indefinite length */
contents_length = -1;
else if ((octet & 0x80) > 0) {
/* Definite (long form) - num octets encoded in 7 rightmost bits */
int num_length_octets = (octet & 0x7F);
for (int i = 0; i < num_length_octets; i++) {
octet = stream.read();
bytes_read[0]++;
contents_length = (contents_length<<8) + octet;
}
} else {
/* Definite (short form) - one length octet. Value encoded in */
/* 7 rightmost bits. */
contents_length = octet;
}
return contents_length;
}
/**
* Writes length octets (definite length only) to stream.
* Uses shortform whenever possible.
* @param stream output stream to write to
* @param num_content_octets value to be encode into length octets
* @return number of bytes sent to stream.
* @exception IOException failed to read octets
*/
public static void sendDefiniteLength(OutputStream stream,
int num_content_octets) throws IOException {
int bytes_written = 0;
if (num_content_octets <= 127) {
/* Use short form */
stream.write(num_content_octets);
} else {
/* Using long form:
* Need to determine how many octets are required to
* encode the length.
*/
int num_length_octets = 0;
int num = num_content_octets;
while (num >= 0) {
num_length_octets++;
num = (num>>8);
if (num <= 0)
break;
}
byte[] buffer = new byte[num_length_octets+1];
buffer[0] = (byte)(0x80 | num_length_octets);
num = num_content_octets;
for (int i = num_length_octets; i > 0; i--) {
buffer[i] = (byte)(num & 0xFF);
num = (num>>8);
}
stream.write(buffer);
}
}
/**
* Reads a number of bytes from an input stream and form
* an integer..
* @param stream source of data
* @param bytes_read number of bytes read
* @param length number of bytes to be read (1 to 4)
* @return the value of the data as two's complement.
* @exception IOException failed to read octets
*/
protected int readUnsignedBinary(InputStream stream,
int[] bytes_read, int length) throws IOException {
int value = 0;
int octet;
for (int i = 0; i < length; i++) {
octet = stream.read();
bytes_read[0]++;
value = (value<<8) + octet;
}
return value;
}
/**
* Reads the two's complement representation of an integer from
* an input stream.
* @param stream source of data
* @param bytes_read number of bytes read
* @param length number of bytes to be read
* @return the integer value as two's complement.
* @exception IOException failed to read octets
*/
protected int readTwosComplement(InputStream stream,
int[] bytes_read, int length) throws IOException {
int value = 0;
if (length > 0) {
boolean negative = false;
int octet = stream.read();
bytes_read[0]++;
if ((octet & 0x80) > 0) /* left-most bit is 1. */
negative = true;
for (int i = 0; i < length; i++) {
if (i > 0) {
octet = stream.read();
bytes_read[0]++;
}
if (negative)
value = (value<<8) + (int)(octet^0xFF)&0xFF;
else
value = (value<<8) + (int)(octet&0xFF);
}
if (negative) /* convert to 2's complement */
value = (value + 1) * -1;
}
return value;
}
/**
* Converts byte to hex string.
* @param value byte value
* @return string representation of Hex String
*/
public String byteToHexString(byte value) {
if (value < 0)
return Integer.toHexString((value & 0x7F) + 128);
else
return Integer.toHexString(value);
}
/**
* Sends the BER encoding directly to a stream.
* @param stream output stream
* @return bytes written to stream.
*/
public abstract void write(OutputStream stream) throws IOException;
/**
* Gets the element type.
* @return element type.
*/
public abstract int getType();
/**
* Gets the string representation.
* @return string representation of an element.
*/
public abstract String toString();
}

View File

@@ -0,0 +1,82 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This class is for the Enumerated object.
* <P>See CCITT X.209.
*
* <pre>
* ENCODING RULE:
* Primitive Definite length.
* tag = 0x0a
* length = (short or long form)
* one or more contents octets hold integral value
* value in two's complement
*
* Example: (Enumerated - 1)
* 0A 01 01
* </pre>
*
* @version 1.0
*/
public class BEREnumerated extends BERIntegral {
/**
* Constructs an enumerated element with a value.
* @param value integral value
*/
public BEREnumerated(int value) {
super(value);
}
/**
* Constructs an enumerated element with the input stream.
* @param stream input stream from which to decode
* @param bytes_read array of 1 int; value incremented by
* number of bytes read from array
* @exception IOException failed to construct
*/
public BEREnumerated(InputStream stream, int[] bytes_read)
throws IOException {
super(stream, bytes_read);
}
/**
* Gets the element type.
* @param element type
*/
public int getType() {
return BERElement.ENUMERATED;
}
/**
* Gets the string representation.
* @return string representation of tag.
*/
public String toString() {
return "Enumerated {" + getValue() + "}";
}
}

View File

@@ -0,0 +1,87 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This class is for the Integer object.
* <P>See CCITT X.209.
*
* <pre>
* ENCODING RULE:
* Primitive Definite length.
* tag = 0x02
* length = (short or long form)
* one or more contents octets hold integer
* value in two's complement
*
* Example 1: (zero)
* 02 01 00
* Example 2: (1)
* 02 01 01
* Example 3: (300 - short form)
* 02 02 01 2C
* Example 4: (300 - long form)
* 02 84 00 00 01 2C
* </pre>
*
* @version 1.0
*/
public class BERInteger extends BERIntegral {
/**
* Constructs a integer element.
* @param value integer value
*/
public BERInteger(int value) {
super(value);
}
/**
* Constructs an integer element with the input stream.
* @param stream input stream
* @param bytes_read array of 1 int; value incremented by
* number of bytes read from stream
* @exception IOException failed to construct
*/
public BERInteger(InputStream stream, int[] bytes_read) throws IOException {
super(stream, bytes_read);
}
/**
* Gets the element type.
* @param element type
*/
public int getType() {
return BERElement.INTEGER;
}
/**
* Gets the string representation.
* @return string representation of tag.
*/
public String toString() {
return "Integer {" + getValue() + "}";
}
}

View File

@@ -0,0 +1,179 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This is the base class for integral types such as Integer and
* Enumerated.
* <P>See CCITT X.209.
*
* <pre>
* ENCODING RULE:
* Primitive Definite length.
* tag = << depends on type >>
* length = (short or long form)
* one or more contents octets hold integral value
* value in two's complement
*
* Example 1: (Integer - zero)
* 02 01 00
* Example 2: (Enumerated - 1)
* 0A 01 01
* Example 3: (Integer - 300, short form)
* 02 02 01 2C
* Example 4: (Integer - 300, long form)
* 02 84 00 00 01 2C
* </pre>
*
* @version 1.0
*/
public abstract class BERIntegral extends BERElement {
/**
* Value of element
*/
private int m_value;
/**
* Constructs an integral type with a value.
* @param value integer value
*/
public BERIntegral(int value) {
m_value = value;
}
/**
* Constructs an integral element from an input stream.
* @param stream source
* @param bytes_read array of 1 int; value incremented by
* number of bytes read from stream
* @exception IOException failed to construct
*/
public BERIntegral(InputStream stream, int[] bytes_read) throws IOException {
int contents_length = super.readLengthOctets(stream, bytes_read);
/* Definite length content octets string. */
if (contents_length > 0) {
boolean negative = false;
int octet = stream.read();
bytes_read[0]++;
if ((octet & 0x80) > 0) /* left-most bit is 1. */
negative = true;
for (int i = 0; i < contents_length; i++) {
if (i > 0) {
octet = stream.read();
bytes_read[0]++;
}
if (negative)
m_value = (m_value<<8) + (int)(octet^0xFF)&0xFF;
else
m_value = (m_value<<8) + (int)(octet&0xFF);
}
if (negative) /* convert to 2's complement */
m_value = (m_value + 1) * -1;
}
}
/**
* Writes BER to stream.
* @param stream output stream
* @exception IOException on failure to write
*/
public void write(OutputStream stream) throws IOException {
int binary_value = m_value;
int num_content_octets = 0;
int total_ber_octets;
int offset=1;
int lead;
int i;
byte[] content_octets = new byte[10]; /* should be plenty big */
byte[] net_octets = new byte[10]; /* pse need this in network order */
/* Get content octets - need to determine length */
if (m_value == 0) {
num_content_octets = 1;
content_octets[offset] = (byte)0x00;
net_octets[offset] = (byte)0x00;
} else {
if (m_value < 0) /* convert from 2's complement */
binary_value = (m_value * -1) -1;
do {
if (m_value < 0)
content_octets[num_content_octets+offset] =
(byte)((binary_value^0xFF)&0xFF);
else
content_octets[num_content_octets+offset] =
(byte)(binary_value&0xFF);
binary_value = (binary_value>>8);
num_content_octets++;
} while (binary_value > 0);
/* pse 1/16/96 we've just created a string that is in non-network order
flip it for net order */
for (i=0; i<num_content_octets; i++)
net_octets[offset+num_content_octets-1-i] = content_octets[offset+i];
/* pse 1/16/96 if we have the value encoded and the leading encoding bit is set
then stuff in a leading zero byte */
lead = (int)net_octets[offset];
if ((m_value > 0) && ((lead & 0x80) > 0)) {
offset = 0;
net_octets[offset] = (byte)0x00;
num_content_octets++;
}
}
stream.write(getType());
sendDefiniteLength(stream, num_content_octets);
stream.write(net_octets,offset,num_content_octets); /* contents */
}
/**
* Gets the integral value.
* @return element value.
*/
public int getValue() {
return m_value;
}
/**
* Gets the element type.
* @return element type.
*/
public abstract int getType();
/**
* Gets the string representation.
* @return string representation of tag.
*/
public abstract String toString();
}

View File

@@ -0,0 +1,91 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This class is for the NULL type.
* <P>See CCITT X.209.
*
* <pre>
* ENCODING RULE:
* tag = 0x05
* length value is zero (short or long form).
* no contents
*
* Example 1: (short form)
* 05 00
* Example 2: (long form)
* 05 81 00
* </pre>
*
* @version 1.0
*/
public class BERNull extends BERElement {
/**
* Constructs a NULL element.
*/
public BERNull() {
}
/**
* Constructs a null element from an input stream.
* @param stream input stream from socket
* @param bytes_read array of 1 int; value incremented by
* number of bytes read from stream
* @exception IOException failed to construct
*/
public BERNull(InputStream stream, int[] bytes_read) throws IOException {
/* The result should be zero of course */
readLengthOctets(stream,bytes_read);
}
/**
* Sends the BER encoding directly to stream.
* @param stream output stream
* @exception IOException failed to write
*/
public void write(OutputStream stream) throws IOException {
byte[] buffer = new byte[2];
buffer[0] = (byte)BERElement.NULL; /* NULL tag */
buffer[1] = 0x00; /* length */
stream.write(buffer);
}
/**
* Gets the element type.
* @return element type.
*/
public int getType() {
return BERElement.NULL;
}
/**
* Gets the string representation.
* @return string representation of tag.
*/
public String toString() {
return "Null {}";
}
}

View File

@@ -0,0 +1,102 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This class is for the NumericString type.
* <P>See CCITT X.209.
*
* <pre>
* ENCODING RULE:
* Primitive Definite length.
* tag = 0x12
* length = (short or long form)
* one or more contents octets
* </pre>
*
* @version 1.0
*/
public class BERNumericString extends BERCharacterString {
/**
* Constructs a numeric string element from a string
* @param buffer string with value of element
*/
public BERNumericString(String string) {
m_value = string;
}
/**
* Constructs a numeric string element from a byte array
* @param buffer buffer
*/
public BERNumericString(byte[] buffer) {
super(buffer);
}
/**
* Constructs a numeric string element from an input stream
* (for constructed encoding)
* @param stream source
* @param bytes_read array of 1 int, incremented by number of bytes read
* @exception IOException failed to construct
*/
public BERNumericString(BERTagDecoder decoder, InputStream stream,
int[] bytes_read) throws IOException {
super(decoder,stream,bytes_read);
}
/**
* Constructs a numericstring element from an input stream
* (for primitive encoding)
* @param stream input stream
* @param bytes_read array of 1 int, incremented by number of bytes read
* @exception IOException failed to construct
*/
public BERNumericString(InputStream stream, int[] bytes_read)
throws IOException {
super(stream,bytes_read);
}
/**
* Gets the element type.
* @return element type.
*/
public int getType() {
return BERElement.NUMERICSTRING;
}
/**
* Gets the string representation. Note that currently prints out
* values in decimal form.
* @return string representation of tag.
*/
public String toString() {
if (m_value == null)
return "NumericString (null)";
else
return "NumericString {" + m_value + "}";
}
}

View File

@@ -0,0 +1,192 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.util.StringTokenizer;
import java.io.*;
/**
* This class is for the Object ID object.
* <P>See CCITT X.209.
*
* @version 1.0
*/
public class BERObjectId extends BERElement {
/**
* Values of each component of the OID
*/
private int[] m_value = null;
/**
* Constructs an object ID element from an array of values.
* @param value object ID value as array of components
*/
public BERObjectId(int[] value) {
m_value = new int[value.length];
System.arraycopy(value,0,m_value,0,value.length);
}
/**
* Constructs an object id element from a string.
* @param value object id value in format "2.100.3"
*/
public BERObjectId(String value) {
StringTokenizer tokenizer = new StringTokenizer(value, ".");
m_value = new int[tokenizer.countTokens()];
for (int i=0; i<m_value.length; i++)
m_value[i] = Integer.parseInt(tokenizer.nextToken());
}
/**
* Constructs an object id element from an input stream.
* @param stream source
* @param bytes_read array of 1 int; value incremented by
* number of bytes read from stream
* @exception IOException failed to construct
*/
public BERObjectId(InputStream stream, int[] bytes_read) throws IOException {
int contents_length = super.readLengthOctets(stream, bytes_read);
bytes_read[0] += contents_length;
int[] contents_read = new int[1];
Vector oid = new Vector(10);
contents_read[0] = 0;
int sub_id = readSubIdentifier(stream, contents_read);
contents_length -= contents_read[0];
if (sub_id < 40)
oid.addElement(new Integer(0));
else if (sub_id < 80)
oid.addElement(new Integer(1));
else
oid.addElement(new Integer(2));
oid.addElement(new Integer(
sub_id - (((Integer)oid.elementAt(
oid.size()-1)).intValue() * 40)));
while (contents_length > 0) {
contents_read[0] = 0;
sub_id = readSubIdentifier(stream, contents_read);
contents_length -= contents_read[0];
oid.addElement(new Integer(sub_id));
}
m_value = new int[oid.size()];
for (int i = 0; i<oid.size(); i++)
m_value[i] = ((Integer)oid.elementAt(i)).intValue();
}
/**
* Sends the BER encoding directly to a stream. Note that OID must
* have >= 2 identifier components (values).
* @param stream output stream
* @exception IOException failed to write
*/
public void write(OutputStream stream) throws IOException {
stream.write(BERElement.OBJECTID);
ByteArrayOutputStream contents_stream = new ByteArrayOutputStream();
/* first subidentifier packs two component values */
writeSubIdentifier(contents_stream,m_value[0]*40 + m_value[1]);
for (int i = 2; i < m_value.length; i++) {
writeSubIdentifier(contents_stream,m_value[i]);
}
byte[] contents_buffer = contents_stream.toByteArray();
sendDefiniteLength(stream, contents_buffer.length);
stream.write(contents_buffer);
}
/**
* Reads a sub identifier from stream.
* @param stream input stream
* @param bytes_read array of 1 int; value incremented by
* number of bytes read from stream
*/
private int readSubIdentifier(InputStream stream, int[] bytes_read)
throws IOException {
int octet;
int sub_id = 0;
do {
octet = stream.read();
bytes_read[0]++;
sub_id = (sub_id << 7) | (octet & 0x7F);
} while ((octet & 0x80) > 0);
return sub_id;
}
/**
* Sends the BER encoding of a sub identifier directly to stream.
* @param stream output stream
* @param value sub-identifier value
*/
private void writeSubIdentifier(OutputStream stream, int value)
throws IOException {
ByteArrayOutputStream sub_id_stream = new ByteArrayOutputStream();
/* gather octets in reverse order */
while (value > 0) {
sub_id_stream.write(value & 0x7F);
value = value >> 7;
}
byte[] sub_id_buffer = sub_id_stream.toByteArray();
for (int i=sub_id_buffer.length-1; i>0; i--) {
/* all but last octet have bit 8 = 1 */
stream.write(sub_id_buffer[i] | 0x80);
}
stream.write(sub_id_buffer[0]); /* last octet has bit 8 = 0 */
}
/**
* Gets the element value.
* @return element value.
*/
public int[] getValue() {
return m_value;
}
/**
* Gets the element type.
* @return element type.
*/
public int getType() {
return BERElement.OBJECTID;
}
/**
* Gets the string representation.
* @return string representation of element.
*/
public String toString() {
if (m_value == null)
return "ObjectIdentifier (null)";
String oid = "";
for (int i = 0; i < m_value.length; i++) {
if (i != 0)
oid = oid + " ";
oid = oid + m_value[i];
}
return "ObjectIdentifier {" + oid + "}";
}
}

View File

@@ -0,0 +1,201 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This class is for the OctetString type.
* <P>See CCITT X.209.
*
* <pre>
* ENCODING RULE:
* Primitive Definite length.
* tag = 0x04
* length = (short or long form)
* one or more contents octets
* </pre>
*
* @version 1.0
*/
public class BEROctetString extends BERElement {
/**
* Raw value of element
*/
private byte[] m_value = null;
/**
* Constructs an octet string element containing a copy of
* the contents of buffer.
* @param buffer a UCS-2 String
*/
public BEROctetString(String buffer) {
if (buffer == null)
return;
try {
m_value = buffer.getBytes( "UTF8" );
} catch (Throwable xxx){};
}
/**
* Constructs an octet string element containing a reference to
* buffer.
* @param buffer a byte array, which must be in UTF-8 format if
* it is string data
*/
public BEROctetString(byte[] buffer) {
m_value = buffer;
}
/**
* Constructs an octet string element containing a
* subset of buffer.
* @param buffer buffer containing 'octets'
* @param start start of buffer range to copy
* @param end end of buffer range to copy
*/
public BEROctetString(byte[] buffer, int start, int end) {
m_value = new byte[end - start];
for (int i = 0; i < end - start; i++)
m_value[i] = buffer[start + i];
}
/**
* Constructs an octet string element from an input stream
* (for constructed encoding)
* @param decoder a decode that understands the specific tags
* @param stream source
* @param bytes_read array of 1 int, incremented by number of bytes read
* @exception IOException failed to construct
*/
public BEROctetString(BERTagDecoder decoder, InputStream stream,
int[] bytes_read) throws IOException {
int octet;
int contents_length = super.readLengthOctets(stream, bytes_read);
int[] component_length = new int[1];
BERElement element = null;
if (contents_length == -1) {
/* Constructed - indefinite length content octets. */
do {
component_length[0] = 0;
element = getElement(decoder,stream,component_length);
if (element != null) {
/* element is an octetstring - add it to the existing buffer */
BEROctetString octet_element = (BEROctetString)element;
byte[] octet_buffer = octet_element.getValue();
if (m_value == null) {
m_value = new byte[octet_buffer.length];
System.arraycopy(octet_buffer,0,
m_value,0,octet_buffer.length);
} else {
byte[] new_buffer = new byte[m_value.length +
octet_buffer.length];
System.arraycopy(m_value,0,new_buffer,0,m_value.length);
System.arraycopy(octet_buffer,0,
new_buffer,m_value.length,
octet_buffer.length);
m_value = new_buffer;
}
}
} while (element != null);
} else {
/* Definite length content octets string. */
bytes_read[0] += contents_length;
m_value = new byte[contents_length];
stream.read(m_value, 0, contents_length);
}
}
/**
* Constructs an octet string element from an input stream
* (for primitive encoding)
* @param stream source
* @param bytes_read array of 1 int, incremented by number of bytes read
* @exception IOException failed to construct
*/
public BEROctetString(InputStream stream, int[] bytes_read)
throws IOException {
int contents_length = super.readLengthOctets(stream, bytes_read);
/* Definite length content octets string. */
if (contents_length > 0) {
m_value = new byte[contents_length];
for (int i = 0; i < contents_length; i++) {
m_value[i] = (byte) stream.read();
}
bytes_read[0] += contents_length;
}
}
/**
* Writes BER to stream
* @return number of bytes written to stream.
* @exception IOException failed to write
*/
public void write(OutputStream stream) throws IOException {
stream.write((byte)BERElement.OCTETSTRING); /* OCTETSTRING tag */
if (m_value == null) {
sendDefiniteLength(stream, 0);
} else {
sendDefiniteLength(stream, m_value.length); /* length */
stream.write(m_value,0,m_value.length); /* contents */
}
}
/**
* Gets the element value.
* @param element value
*/
public byte[] getValue() {
return m_value;
}
/**
* Gets the element type.
* @param element type
*/
public int getType() {
return BERElement.OCTETSTRING;
}
/**
* Gets the string representation.
* NOTE: currently prints out values in decimal form.
* @return string representation of tag.
*/
public String toString() {
if (m_value == null)
return "OctetString (null)";
String octets = "";
for (int i = 0; i < m_value.length; i++) {
if (i != 0)
octets = octets + " ";
octets = octets + byteToHexString(m_value[i]);
}
return "OctetString {" + octets + "}";
}
}

View File

@@ -0,0 +1,102 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This class is for the PrintableString type.
* <P>See CCITT X.209.
*
* <pre>
* ENCODING RULE:
* Primitive Definite length.
* tag = 0x13
* length = (short or long form)
* one or more contents octets
* </pre>
*
* @version 1.0
*/
public class BERPrintableString extends BERCharacterString {
/**
* Constructs a printable string element containing buffer.
* @param buffer string value
*/
public BERPrintableString(String string) {
m_value = string;
}
/**
* Constructs a printables tring element from buffer.
* @param buffer byte array value
*/
public BERPrintableString(byte[] buffer) {
super(buffer);
}
/**
* Constructs a printable string element from an input stream
* (for constructed encoding)
* @param stream source
* @param bytes_read array of 1 int, incremented by number of bytes read
* @exception IOException failed to construct
*/
public BERPrintableString(BERTagDecoder decoder, InputStream stream,
int[] bytes_read) throws IOException {
super(decoder,stream,bytes_read);
}
/**
* Constructs a printablestring element from an input stream
* (for primitive encoding)
* @param stream source
* @param bytes_read array of 1 int, incremented by number of bytes read
* @exception IOException failed to construct
*/
public BERPrintableString(InputStream stream, int[] bytes_read)
throws IOException {
super(stream,bytes_read);
}
/**
* Gets the element type.
* @return element type.
*/
public int getType() {
return BERElement.PRINTABLESTRING;
}
/**
* Gets the string representation. Note that it prints out
* values in decimal form.
* @return string representation of tag.
*/
public String toString() {
if (m_value == null)
return "PrintableString (null)";
else
return "PrintableString {" + m_value + "}";
}
}

View File

@@ -0,0 +1,213 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This class is for the Real object.
* <P>See CCITT X.209.
*
* <pre>
* ENCODING RULE:
* tag = 0x09
* </pre>
*
* @version 1.0
*/
public class BERReal extends BERElement {
/**
* Constants: special ASN.1 real values
*/
public final static float PLUS_INFINITY = 1.0f/0.0f;
public final static float MINUS_INFINITY = -1.0f/0.0f;
/**
* Value of element
*/
private float m_value = 0;
/**
* Constructs a real element with a value
* @param value float value
*/
public BERReal(float value) {
m_value = value;
}
/**
* Constructs a real element from an input stream.
* @param stream source
* @param bytes_read array of 1 int; value incremented by
* number of bytes read from stream.
* @exception IOException failed to construct
*/
public BERReal(InputStream stream, int[] bytes_read) throws IOException {
int length = super.readLengthOctets(stream, bytes_read);
if (length == 0)
/* zero length indicates value is zero */
m_value = 0;
else {
int octet = stream.read(); /* first content octet */
bytes_read[0]++;
if (octet == 0x40) /* bit 8 = 1 */
m_value = PLUS_INFINITY;
else if (octet == 0x41) /* bit 8 = 1 and bit 1 = 1 */
m_value = MINUS_INFINITY;
else if ((octet & 0x80) > 0) {
/* bit 8 = 1 */
/* Binary encoding */
/* M = S*N*2F where S = -1 or 1, 0<= F <= 3. */
int sign;
int base;
int number;
int f; /* binary scaling factor */
int exponent;
int mantissa;
int num_exponent_octets;
int contents_length_left;
if ((octet & 0x40) > 0) sign = -1;
else sign = 1;
if ((octet & 0x20) > 0) {
if ((octet & 0x10) > 0) {
/* bits 6+5 = 11 */
/* reserved for future use */
base = 0;
} else {
/* bits 6+5 = 10 */
base = 16;
}
} else if ((octet & 0x10) > 0) {
/* bits 6+5 = 01 */
base = 8;
} else {
/* bits 6+5 = 00 */
base = 2;
}
if ((octet & 0x08) > 0) {
if ((octet & 0x04) > 0) {
/* bits 4+3 = 11 */
f = 3;
} else {
/* bits 4+3 = 10 */
f = 2;
}
} else if ((octet & 0x04) > 0) {
/* bits 4+3 = 01 */
f = 1;
} else {
/* bits 4+3 = 00 */
f = 0;
}
if ((octet & 0x02) > 0) {
if ((octet & 0x01) > 0) {
/* bits 2+1 = 11 */
/* Following octet encodes the number of octets used to
* encode the exponent.
*/
num_exponent_octets = stream.read();
bytes_read[0]++;
exponent = readTwosComplement(stream,bytes_read,num_exponent_octets);
} else {
/* bits 2+1 = 10 */
num_exponent_octets = 3;
exponent = readTwosComplement(stream,bytes_read,num_exponent_octets);
}
} else if ((octet & 0x01) > 0) {
/* bits 2+1 = 01 */
num_exponent_octets = 2;
exponent = readTwosComplement(stream,bytes_read,num_exponent_octets);
} else {
/* bits 2+1 = 00 */
num_exponent_octets = 1;
exponent = readTwosComplement(stream,bytes_read,num_exponent_octets);
}
contents_length_left = length - 1 - num_exponent_octets;
number = readUnsignedBinary(stream, bytes_read, contents_length_left);
mantissa = (int)(sign * number * Math.pow(2, f));
m_value = mantissa * (float)Math.pow((double)base,(double)exponent);
} else {
/* bits 8 + 7 = 00 */
/* ISO 6093 field */
/*** NOTE: It has been agreed that this feature will
* not be provided right now.
*/
throw new IOException("real ISO6093 not supported. ");
}
}
}
/**
* Sends the BER encoding directly to a stream.
* @param stream output stream
* @exception IOException failed to write
*/
public void write(OutputStream stream) throws IOException {
if (m_value == 0) {
stream.write(BERElement.REAL);
stream.write(0x00); /* length */
} else if (m_value == PLUS_INFINITY) {
stream.write(BERElement.REAL);
stream.write(0x01); /* length */
stream.write(0x40); /* contents */
} else if (m_value == MINUS_INFINITY) {
stream.write(BERElement.REAL);
stream.write(0x01); /* length */
stream.write(0x41); /* contents */
} else {
/* Non-special real value */
/* NOTE: currently always sends as a base 2 binary encoding
* (see X.2 09 section 10.5.)
*
* M = S * N * 2F
*
* Simple encoding always uses F = 1.
*/
// bcm - incomplete.
}
}
/**
* Gets the element type.
* @return element type
*/
public int getType() {
return BERElement.REAL;
}
/**
* Gets the string representation.
* @return string representation of tag
*/
public String toString() {
return "Real {" + m_value + "}";
}
}

View File

@@ -0,0 +1,82 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This class is for the Sequence object. A sequence object can
* contains a sequence of BER Elements.
* <P>See CCITT X.209.
*
* <pre>
* ENCODING RULE:
* tag = 0x30 (always constructed)
* </pre>
*
* @version 1.0
*/
public class BERSequence extends BERConstruct {
/**
* Constructs a sequence element.
*/
public BERSequence() {
super();
}
/**
* Constructs a sequence element from an input stream.
* @param decoder application-specific BER decoder
* @param stream input stream from which to read BER
* @param bytes_read array of 1 int; value is incremented by
* number of bytes read from stream
* @exception IOException failed to construct
*/
public BERSequence(BERTagDecoder decoder, InputStream stream,
int[] bytes_read) throws IOException {
super(decoder, stream, bytes_read);
}
/**
* Gets the element type.
* @return element type.
*/
public int getType() {
return BERElement.SEQUENCE;
}
/**
* Gets the string representation.
* @return string representation of tag.
*/
public String toString() {
String elements = "";
for (int i = 0; i < super.size(); i++) {
if (i != 0)
elements = elements + ", ";
elements = elements + ((BERElement)super.elementAt(i)).toString();
}
return "Sequence {" + elements + "}";
}
}

View File

@@ -0,0 +1,90 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This class is for the Set object. A set object can contain
* a set of BER elements.
* <P>See CCITT X.209.
*
* <pre>
* ENCODING RULE:
* tag = 0x31 (always constructed)
* </pre>
*
* @version 1.0
*/
public class BERSet extends BERConstruct {
/**
* Constructs a set element.
* @exception failed to construct
*/
public BERSet() throws IOException {
}
/**
* Constructs a set element from an input stream.
* @param decoder decoder for application-specific BER
* @param stream source
* @param bytes_read array of 1 int; value incremented by number
* of bytes read from stream
* @exception IOException failed to construct
*/
public BERSet(BERTagDecoder decoder, InputStream stream,
int[] bytes_read) throws IOException {
super(decoder, stream,bytes_read);
}
/**
* Sends the BER encoding directly to a stream.
* @param stream output stream
* @exception IOException failed to write
*/
public void write(OutputStream stream) throws IOException {
super.write(stream);
}
/**
* Gets the element type.
* @return element type.
*/
public int getType() {
return BERElement.SET;
}
/**
* Gets the string representation.
* @return string representation of tag.
*/
public String toString() {
String elements = "";
for (int i = 0; i < super.size(); i++) {
if (i != 0)
elements = elements + ", ";
elements = elements + ((BERElement)super.elementAt(i)).toString();
}
return "Set {" + elements + "}";
}
}

View File

@@ -0,0 +1,168 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This class is for the tagged object type. A nested tag is
* allowed. A tagged element contains another
* ber element.
* <P>See CCITT X.209.
*
* <pre>
* ENCODING RULE:
* tag = whatever it is constructed with
* </pre>
*
* @version 1.0
*/
public class BERTag extends BERElement {
/**
* Value of tag
*/
private int m_tag = 0;
/**
* Value of element
*/
private BERElement m_element = null;
/**
* Implicit or not
*/
private boolean m_implicit = false;
/**
* Constructs a tag element.
* @param tag tag value
* @param element ber element
* @param implicit tagged implicitly
*/
public BERTag(int tag, BERElement element, boolean implicit) {
m_tag = tag;
m_element = element;
m_implicit = implicit;
}
/**
* Constructs a tag element from an input stream.
* @param decoder decoder object for application-specific tags
* @param tag tag value; already stripped from stream
* @param stream source
* @param bytes_read array of 1 int; incremented by number
* of bytes read from stream
* @exception IOException failed to construct
*/
public BERTag(BERTagDecoder decoder, int tag, InputStream stream,
int[] bytes_read) throws IOException {
m_tag = tag;
boolean[] implicit = new boolean[1];
/*
* Need to use user callback to decode contents of
* a non-universal tagged value.
*/
m_element = decoder.getElement(decoder, tag, stream, bytes_read,
implicit);
m_implicit = implicit[0];
}
/**
* Gets the element from the tagged object.
* @return BER element.
*/
public BERElement getValue() {
return m_element;
}
/**
* Sets the implicit tag. If it is an implicit tag,
* the next element tag can be omitted (it will
* not be sent to a stream or buffer).
* @param value implicit flag
*/
public void setImplicit(boolean value) {
m_implicit = value;
}
/**
* Sends the BER encoding directly to a stream.
* @param stream output stream
* @exception IOException failed to send
*/
public void write(OutputStream stream) throws IOException {
stream.write(m_tag); /* bcm - assuming tag is one byte */
ByteArrayOutputStream contents_stream = new ByteArrayOutputStream();
m_element.write(contents_stream);
byte[] contents_buffer = contents_stream.toByteArray();
if (m_implicit) {
/* Assumes tag is only one byte. Rest of buffer is */
/* length and contents of tagged element. */
stream.write(contents_buffer, 1, contents_buffer.length -1);
} else {
/* Send length */
sendDefiniteLength(stream, contents_buffer.length);
/* Send contents */
stream.write(contents_buffer);
}
}
/**
* Gets the element type.
* @return element type.
*/
public int getType() {
return BERElement.TAG;
}
/**
* Gets the element tag.
* @return element tag.
*/
public int getTag() {
return m_tag;
}
/**
* Gets the string representation.
* @return string representation of tag.
*/
public String toString() {
String s = "";
if ((m_tag & 0xC0) == 0)
/* bits 8 + 7 are zeros */
s = s + "UNIVERSAL-";
else if (((m_tag & 0x80) & (m_tag & 0x40)) > 0)
/* bits 8 + 7 are ones */
s = s + "PRIVATE-";
else if ((m_tag & 0x40) > 0)
/* bit 8 is zero, bit 7 is one */
s = s + "APPLICATION-";
else if ((m_tag & 0x80) > 0)
/* bit 8 is one, bit 7 is zero */
s = s + "CONTEXT-";
return "[" + s + (m_tag&0x1f) + "] " + m_element.toString();
}
}

View File

@@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This is an abstract class which should be extended
* for use by the BERTag class in decoding application
* specific BER tags. Since different applications may
* define their own tag, the BER package needs a tag decoder
* to give hints on how to decode implicitly tagged
* objects. Each application should extend this
* decoder.
*
* @version 1.0
*/
public abstract class BERTagDecoder {
/**
* Gets an application specific ber element from an input stream.
* @param decoder an instance of a BERTagDecoder
* @param tag element tag
* @param stream source stream
* @param bytes_read array of 1 int; value incremented by number
* of bytes read from stream
* @param implicit array of implicit flags
*/
public abstract BERElement getElement(BERTagDecoder decoder, int tag,
InputStream stream, int[] bytes_read, boolean[] implicit)
throws IOException;
}

View File

@@ -0,0 +1,172 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This class is for the UTCTime object.
* <P>See CCITT X.209.
*
* <pre>
* ENCODING RULE:
* Primitive Definite length.
* tag = 0x17
* length = (short or long form)
* one or more contents octets
* </pre>
*
* @version 1.0
*/
public class BERUTCTime extends BERElement {
/**
* Internal variables
*/
private String m_value = null;
/**
* Constructs a UTC time element containing the specified string.
* @param utc_string string in UTC time format
*/
public BERUTCTime(String utc_string) {
m_value = utc_string;
}
/**
* Constructs a UTCTime element from an input stream
* (for constructed encoding)
* @param stream source
* @param bytes_read array of 1 int, incremented by number of bytes read
* @exception IOException failed to construct
*/
public BERUTCTime(BERTagDecoder decoder, InputStream stream,
int[] bytes_read) throws IOException {
int octet;
int contents_length = super.readLengthOctets(stream, bytes_read);
int[] component_length = new int[1];
BERElement element = null;
m_value = "";
if (contents_length == -1) {
/* Constructed - indefinite length content octets. */
{
component_length[0] = 0;
element = getElement(decoder,stream,component_length);
if (element != null) {
/* element is an octetstring - add it to the existing buffer */
BERUTCTime utc_element = (BERUTCTime)element;
m_value += utc_element.getValue();
}
} while (element != null);
} else {
/* Definite length content octets string. */
bytes_read[0] += contents_length;
while (contents_length > 0) {
component_length[0] = 0;
element = getElement(decoder,stream,component_length);
if (element != null) {
/* element is an octetstring - add it to the existing buffer */
BERUTCTime utc_element = (BERUTCTime)element;
m_value += utc_element.getValue();
}
contents_length -= component_length[0];
}
}
}
/**
* Constructs a UTC time element from an input stream
* (for primitive encoding)
* @param stream source
* @param bytes_read array of 1 int, incremented by number of bytes read
* @exception IOException failed to construct
*/
public BERUTCTime(InputStream stream, int[] bytes_read) throws IOException {
int contents_length = super.readLengthOctets(stream, bytes_read);
/* Definite length content octets string. */
if (contents_length > 0) {
byte[] byte_buf = new byte[contents_length];
for (int i = 0; i < contents_length; i++) {
byte_buf[i] = (byte) stream.read();
}
bytes_read[0] += contents_length;
try{
m_value = new String(byte_buf, "UTF8");
} catch(Throwable x)
{}
}
}
/**
* Writes BER to a stream.
* @return number of bytes written to stream.
* @exception IOException failed to write
*/
private byte[] byte_buf;
public void write(OutputStream stream) throws IOException {
stream.write((byte)getType());
if (m_value == null) {
sendDefiniteLength(stream, 0);
} else {
try{
byte_buf = m_value.getBytes("UTF8");
sendDefiniteLength(stream, byte_buf.length); /* length */
} catch(Throwable x)
{}
stream.write(byte_buf,0,byte_buf.length); /* contents */
}
}
/**
* Gets the element value.
* @param element value
*/
public String getValue() {
return m_value;
}
/**
* Gets the element type.
* @param element type
*/
public int getType() {
return BERElement.UTCTIME;
}
/**
* Gets the string representation.
* NOTE: currently prints out values in decimal form.
* @return string representation of tag.
*/
public String toString() {
if (m_value == null)
return "UTCTime (null)";
else
return "UTCTime {" + m_value + "}";
}
}

View File

@@ -0,0 +1,102 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.ber.stream;
import java.util.*;
import java.io.*;
/**
* This class is for the VisibleString object.
* <P>See CCITT X.209.
*
* <pre>
* ENCODING RULE:
* Primitive Definite length.
* tag = 0x1A
* length = (short or long form)
* one or more contents octets
* </pre>
*
* @version 1.0
*/
public class BERVisibleString extends BERCharacterString {
/**
* Constructs a visiblestring element.
* @param string string
*/
public BERVisibleString(String string) {
m_value = string;
}
/**
* Constructs a visiblestring element from buffer.
* @param buffer buffer
*/
public BERVisibleString(byte[] buffer) {
super(buffer);
}
/**
* Constructs a visiblestring element with the input stream.
* (for constructed encoding)
* @param stream input stream
* @param bytes_read array of 1 int, incremented by number of bytes read
* @exception IOException failed to construct
*/
public BERVisibleString(BERTagDecoder decoder, InputStream stream,
int[] bytes_read) throws IOException {
super(decoder,stream,bytes_read);
}
/**
* Constructs a visiblestring element with the input stream.
* (for primitive encoding)
* @param stream input stream
* @param bytes_read array of 1 int, incremented by number of bytes read
* @exception IOException failed to construct
*/
public BERVisibleString(InputStream stream, int[] bytes_read)
throws IOException {
super(stream,bytes_read);
}
/**
* Gets the element type.
* @param element type
*/
public int getType() {
return BERElement.VISIBLESTRING;
}
/**
* Gets the string representation. Note that currently prints out
* values in decimal form.
* @return string representation of tag.
*/
public String toString() {
if (m_value == null)
return "VisibleString (null)";
return "VisibleString {" + m_value + "}";
}
}

View File

@@ -0,0 +1,101 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client;
import java.util.*;
import java.io.*;
import org.ietf.ldap.ber.stream.*;
/**
* This class implements the attribute value assertion.
* This object is used with filters.
* <pre>
* AttributeValueAssertion ::= SEQUENCE {
* attributType AttributeType,
* attributValue AttributeValue
* }
* </pre>
*
* @version 1.0
*/
public class JDAPAVA {
/**
* Internal variables
*/
protected String m_type = null;
protected String m_val = null;
/**
* Constructs the attribute value assertion.
* @param type attribute type
* @param val attribute value
*/
public JDAPAVA(String type, String val) {
m_type = type;
m_val = val;
}
/**
* Retrieves the AVA type.
* @return AVA type
*/
public String getType() {
return m_type;
}
/**
* Retrieves the AVA value.
* @return AVA value
*/
public String getValue() {
return m_val;
}
/**
* Retrieves the ber representation.
* @return ber representation
*/
public BERElement getBERElement() {
BERSequence seq = new BERSequence();
seq.addElement(new BEROctetString(m_type));
seq.addElement(JDAPFilterOpers.getOctetString(m_val));
return seq;
}
/**
* Retrieves the string representation parameters.
* @return string representation parameters
*/
public String getParamString() {
return "{type=" + m_type + ", value=" + m_val + "}";
}
/**
* Retrieves the string representation.
* @return string representation
*/
public String toString() {
return "JDAPAVA " + getParamString();
}
}

View File

@@ -0,0 +1,123 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client;
import java.util.*;
import org.ietf.ldap.ber.stream.*;
import java.io.*;
/**
* This class is to help BER libraries to make decision
* on how to decode an implicit object.
*/
public class JDAPBERTagDecoder extends BERTagDecoder {
/**
* Gets an application specific ber element from the stream.
* @param buffer ber encoding buffer
* @param stream input stream
* @param bytes_read number of bytes read
* @param implicit to indicate a tag implicit or not
*/
public BERElement getElement(BERTagDecoder decoder, int tag,
InputStream stream, int[] bytes_read, boolean[] implicit)
throws IOException {
BERElement element = null;
switch (tag) {
case 0x60: /* [APPLICATION 0] For Bind Request */
case 0x61: /* [APPLICATION 1] Bind Response */
case 0x63: /* [APPLICATION 3] Search Request
* If doing search without bind first,
* x500.arc.nasa.gov returns tag [APPLICATION 3]
* in Search Response. Gee.
*/
case 0x64: /* [APPLICATION 4] Search Response */
case 0x65: /* [APPLICATION 5] Search Result */
case 0x67: /* [APPLICATION 7] Modify Response */
case 0x69: /* [APPLICATION 9] Add Response */
case 0x6a: /* [APPLICATION 10] Del Request */
case 0x6b: /* [APPLICATION 11] Del Response */
case 0x6d: /* [APPLICATION 13] ModifyRDN Response */
case 0x6f: /* [APPLICATION 15] Compare Response */
case 0x78: /* [APPLICATION 23] Extended Response */
case 0x73: /* [APPLICATION 19] SearchResultReference */
element = new BERSequence(decoder, stream, bytes_read);
implicit[0] = true;
break;
case 0x80: /* [APPLICATION 16] 64+16 */
element = new BERInteger(stream, bytes_read);
implicit[0] = true;
break;
/* 16/02/97 MS specific */
case 0x85: /* Context Specific [5]:
* (a) Handle Microsoft v3 referral bugs! (Response)
* (b) Handle Microsoft v3 supportedVersion in Bind
* response
*/
element = new BERInteger(stream, bytes_read);
implicit[0] = true;
break;
case 0x87: /* Context Specific [7]:
* Handle Microsoft Filter "present" in
* search request.
*/
element = new BEROctetString(decoder, stream, bytes_read);
implicit[0] = true;
break;
case 0x8a: /* Context Specific [10]:
* Handle extended response
*/
element = new BEROctetString(decoder, stream, bytes_read);
implicit[0] = true;
break;
case 0x8b: /* Context Specific [11]:
* Handle extended response
*/
element = new BEROctetString(decoder, stream, bytes_read);
implicit[0] = true;
break;
case 0xa3: /* Context Specific <Construct> [3]:
* Handle Microsoft v3 sasl bind request
*/
element = new BERSequence(decoder, stream, bytes_read);
implicit[0] = true;
break;
case 0xa7: /* Context Specific <Construct> [7]:
* Handle Microsoft v3 serverCred in
* bind response. MS encodes it as SEQUENCE OF
* while it should be CHOICE OF.
*/
element = new BERSequence(decoder, stream, bytes_read);
implicit[0] = true;
break;
case 0xa0: /* Context Specific <Construct> [0]:
* v3 Server Control.
* SEQUENCE of SEQUENCE of {OID [critical] [value]}
*/
element = new BERSequence(decoder, stream, bytes_read);
implicit[0] = true;
break;
default:
throw new IOException();
}
return element;
}
}

View File

@@ -0,0 +1,255 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client;
import java.util.*;
import org.ietf.ldap.ber.stream.*;
import java.io.*;
/**
* This class implements the filter.
* <pre>
* Filter ::= CHOICE {
* and [0] SET OF Filter,
* or [1] SET OF Filter,
* not [2] Filter,
* equalityMatch [3] AttributeValueAssertion,
* substrings [4] SubstringFilter,
* greaterOrEqual [5] AttributeValueAssertion,
* lessOrEqual [6] AttributeValueAssertion,
* present [7] AttributeType,
* approxMatch [8] AttributeValueAssertion
* }
* </pre>
*
* @version 1.0
*/
public abstract class JDAPFilter {
/**
* Constructs a empty filter.
*/
public JDAPFilter() {
}
/**
* Constructs filter from filter string specified in RFC1558.
* <pre>
* <filter> ::= '(' <filtercomp> ')'
* <filtercomp> ::= <and> | <or> | <not> | <item>
* <and> ::= '&' <filterlist>
* <or> ::= '|' <filterlist>
* <not> ::= '!' <filter>
* <filterlist> ::= <filter> | <filter> <filterlist>
* <item> ::= <simple> | <present> | <substring>
* <simple> ::= <attr> <filtertype> <value>
* <filtertype> ::= <equal> | <approx> | <greater> | <less>
* <equal> ::= '='
* <approx> ::= '~='
* <greater> ::= '>='
* <less> ::= '<='
* <present> ::= <attr> '=*'
* <substring> ::= <attr> '=' <initial> <any> <final>
* <initial> ::= NULL | <value>
* <any> ::= '*' <starval>
* <starval> ::= NULL | <value> '*' <starval>
* <final> ::= NULL | <value>
* </pre>
* @param dn distinguished name of adding entry
* @param attrs list of attribute associated with entry
* @return filter
*/
public static JDAPFilter getFilter(String filter) {
String f = new String(filter);
f.trim();
if (f.startsWith("(") && f.endsWith(")")) {
return getFilterComp(f.substring(1,f.length()-1));
}
return getFilterComp(filter);
}
/**
* Constructs the filter computation.
* @param f filter string within brackets
* @return filter
*/
public static JDAPFilter getFilterComp(String f) {
f.trim();
if (f.startsWith("&")) { /* and */
JDAPFilter filters[] = getFilterList(f.substring(1, f.length()));
if (filters == null) {
throw new IllegalArgumentException("Bad search filter");
}
JDAPFilterAnd and = new JDAPFilterAnd();
for (int i = 0; i < filters.length; i++) {
and.addElement(filters[i]);
}
return and;
} else if (f.startsWith("|")) { /* or */
JDAPFilter filters[] = getFilterList(f.substring(1, f.length()));
if (filters == null) {
throw new IllegalArgumentException("Bad search filter");
}
JDAPFilterOr or = new JDAPFilterOr();
for (int i = 0; i < filters.length; i++) {
or.addElement(filters[i]);
}
return or;
} else if (f.startsWith("!")) { /* not */
JDAPFilter filter = getFilter(f.substring(1, f.length()));
if (filter == null) {
throw new IllegalArgumentException("Bad search filter");
}
return new JDAPFilterNot(filter);
} else { /* item */
return getFilterItem(f.substring(0, f.length()));
}
}
/**
* Parses a list of filters
* @param list filter list (i.e. (filter)(filter)...)
* @return list of filters
*/
public static JDAPFilter[] getFilterList(String list) {
list.trim();
int level = 0;
int start = 0;
int end = 0;
Vector v = new Vector();
for (int i = 0; i < list.length(); i++) {
if (list.charAt(i) == '(') {
if (level == 0) {
start = i;
}
level++;
}
if (list.charAt(i) == ')') {
level--;
if (level == 0) {
end = i;
v.addElement(JDAPFilter.getFilter(list.substring(start, end+1)));
}
}
}
if (v.size() == 0)
return null;
JDAPFilter f[] = new JDAPFilter[v.size()];
for (int i = 0; i < v.size(); i++) {
f[i] = (JDAPFilter)v.elementAt(i);
}
return f;
}
/**
* Gets filter item.
* @param item filter item string
* @return filter
*/
public static JDAPFilter getFilterItem(String item) {
item.trim();
int idx = item.indexOf('=');
if (idx == -1)
return null;
String type = item.substring(0, idx).trim();
String value = item.substring(idx+1).trim(); /* skip = */
// Only values can contain escape sequences
if (type.indexOf('\\') >= 0) {
throw new IllegalArgumentException("Bad search filter");
}
/* make decision by looking at the type */
type.trim();
if (type.endsWith("~")) {
JDAPAVA ava = new
JDAPAVA(type.substring(0, type.length()-1), value);
return new JDAPFilterApproxMatch(ava);
} else if (type.endsWith(">")) {
JDAPAVA ava = new
JDAPAVA(type.substring(0, type.length()-1), value);
return new JDAPFilterGreaterOrEqual(ava);
} else if (type.endsWith("<")) {
JDAPAVA ava = new
JDAPAVA(type.substring(0, type.length()-1), value);
return new JDAPFilterLessOrEqual(ava);
} else if (type.endsWith(":")) {
return new JDAPFilterExtensible(type.substring(0, type.length()-1), value);
}
/* for those that are not simple */
if (value.startsWith("*") && value.length() == 1) {
return new JDAPFilterPresent(type);
}
/* if value contains no '*', then it is equality */
if (value.indexOf('*') == -1) {
JDAPAVA ava = new JDAPAVA(type, value);
return new JDAPFilterEqualityMatch(ava);
}
/* must be substring at this point */
StringTokenizer st = new StringTokenizer(value, "*");
JDAPFilterSubString sub = new JDAPFilterSubString(type);
String initial = null;
if (!value.startsWith("*")) {
initial = st.nextToken();
initial.trim();
}
sub.addInitial(initial);
while (st.hasMoreTokens()) {
String any = st.nextToken();
any.trim();
if (st.hasMoreTokens()) {
sub.addAny(any);
} else {
if (value.endsWith("*")) {
sub.addAny(any);
sub.addFinal(null);
} else {
sub.addFinal(any);
}
}
}
return sub;
}
/**
* Gets the ber representation of filter.
* @return ber representation of filter
*/
public abstract BERElement getBERElement();
/**
* Retrieves the string representation of filter.
* @return string representation of filter
*/
public abstract String toString();
}

View File

@@ -0,0 +1,67 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client;
import java.util.*;
import org.ietf.ldap.ber.stream.*;
import java.io.*;
/**
* This class implements the attribute value assertion filter.
*
* @version 1.0
*/
public abstract class JDAPFilterAVA extends JDAPFilter {
/**
* Internal variables
*/
private int m_tag;
private JDAPAVA m_ava = null;
/**
* Constructs base filter for other attribute value assertion.
* @param tag attribute tag
* @param ava attribute value assertion
*/
public JDAPFilterAVA(int tag,
JDAPAVA ava) {
m_tag = tag;
m_ava = ava;
}
/**
* Get attribute value assertion.
* @return value assertion
*/
public JDAPAVA getAVA() {
return m_ava;
}
/**
* Gets the ber representation of the filter.
* @return ber representation
*/
public BERElement getBERElement() {
BERTag element = new BERTag(m_tag, m_ava.getBERElement(), true);
return element;
}
}

View File

@@ -0,0 +1,51 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client;
import java.util.*;
import org.ietf.ldap.ber.stream.*;
import java.io.*;
/**
* This class implements the filter And.
* <pre>
* and [0] SET OF Filter
* </pre>
*
* @version 1.0
*/
public class JDAPFilterAnd extends JDAPFilterSet {
/**
* Constructs the filter.
*/
public JDAPFilterAnd() {
super(BERTag.CONSTRUCTED|BERTag.CONTEXT|0);
}
/**
* Gets string reprensetation of the filter.
* @return string representation
*/
public String toString() {
return "JDAPFilterAnd {" + super.getParamString() + "}";
}
}

View File

@@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client;
import java.util.*;
import org.ietf.ldap.ber.stream.*;
import java.io.*;
/**
* This class implements the approximate match filter.
* <pre>
* approxMatch [8] AttributeValueAssertion
* </pre>
*
* @version 1.0
*/
public class JDAPFilterApproxMatch extends JDAPFilterAVA {
/**
* Constructs approximate match filter.
* @param ava attribute value assertion
*/
public JDAPFilterApproxMatch(JDAPAVA ava) {
super(BERTag.CONSTRUCTED|BERTag.CONTEXT|8, ava);
}
/**
* Retrieves the string representation of the filter.
* @return string representation
*/
public String toString() {
return "JDAPFilterApproximateMatch {" +
super.getAVA().toString() + "}";
}
}

View File

@@ -0,0 +1,54 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client;
import java.util.*;
import org.ietf.ldap.ber.stream.*;
import java.io.*;
/**
* This class implements the equality match filter.
* <P>See RFC 1777.
* <pre>
* equalityMatch [3] AttributeValueAssertion
* </pre>
*
* @version 1.0
*/
public class JDAPFilterEqualityMatch extends JDAPFilterAVA {
/**
* Constructs less or equal filter.
* @param ava attribute value assertion
*/
public JDAPFilterEqualityMatch(JDAPAVA ava) {
super(BERTag.CONSTRUCTED|BERTag.CONTEXT|3, ava);
}
/**
* Retrieves the string representation of the filter.
* @return string representation
*/
public String toString() {
return "JDAPFilterEqualityMatch {" +
super.getAVA().toString() + "}";
}
}

View File

@@ -0,0 +1,132 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client;
import java.util.*;
import org.ietf.ldap.ber.stream.*;
import java.io.*;
/**
* This class implements the extended match filter.
* <pre>
* extensibleMatch [9] AttributeValueAssertion
* </pre>
*
* @version 1.0
*/
public class JDAPFilterExtensible extends JDAPFilter {
/**
* Constructs extensible match filter.
* @param match Matching rule assertion
*/
public JDAPFilterExtensible(String type, String match) {
m_tag = BERTag.CONSTRUCTED|BERTag.CONTEXT|9;
m_type = type;
m_value = match;
}
/**
* Gets ber representation of the filter.
* <PRE>
* Extended filter: [type] [':dn'][':'oid]':='value
*
* BER: extensibleMatch [9] MatchingRuleAssertion
* MatchingRuleAssertion ::= SEQUENCE {
* matchingRule [1] MatchingRuleID OPTIONAL,
* type [2] AttributeDescription OPTIONAL,
* matchValue [3] AssertionValue,
* dnAttributes [4] BOOLEAN DEFAULT FALSE
* }
* </PRE>
* @return ber representation
*/
public BERElement getBERElement() {
String value = m_value;
String defs = m_type;
/* Need either ':dn' or ':'oid */
int colonIndex = defs.lastIndexOf(':');
if ( colonIndex == -1 ) {
return null;
}
/* Is it dn or oid? */
boolean isDN = false;
String oid = null;
if ( defs.regionMatches( true, colonIndex+1, "dn", 0, 2 ) )
isDN = true;
else
oid = defs.substring( colonIndex+1 );
/* Any more? */
defs = defs.substring( 0, colonIndex );
colonIndex = defs.lastIndexOf(':');
if ( colonIndex >= 0 ) {
/* Is it dn or oid? */
if ( defs.regionMatches( true, colonIndex+1, "dn", 0, 2 ) )
isDN = true;
else
oid = defs.substring( colonIndex+1 );
}
BERSequence seq = new BERSequence();
BERTag tag;
/* Was there an oid? */
if ( oid != null ) {
tag = new BERTag( BERTag.CONTEXT|BERTag.MRA_OID, new
BEROctetString(oid), true );
seq.addElement( tag );
}
/* Was there an attribute description? */
if ( defs.length() > 0 ) {
tag = new BERTag( BERTag.CONTEXT|BERTag.MRA_TYPE, new
BEROctetString(defs), true );
seq.addElement( tag );
}
/* Got to have a value */
tag = new BERTag( BERTag.CONTEXT|BERTag.MRA_VALUE, new
BEROctetString(value), true );
seq.addElement( tag );
/* Was ':dn' specified? */
tag = new BERTag( BERTag.CONTEXT|BERTag.MRA_DNATTRS, new
BERBoolean(isDN), true );
seq.addElement( tag );
BERTag element = new BERTag( m_tag, seq, true );
return element;
}
/**
* Retrieves the string representation of the filter.
* @return string representation
*/
public String toString() {
return "JDAPFilterExtensible {" + m_value + "}";
}
private int m_tag;
private String m_type = null;
private String m_value = null;
}

View File

@@ -0,0 +1,55 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client;
import java.util.*;
import org.ietf.ldap.ber.stream.*;
import java.io.*;
/**
* This class implements the greater or equal filter.
* <P>See RFC 1777.
*
* <pre>
* greaterOrEqual [5] AttributeValueAssertion
* </pre>
*
* @version 1.0
*/
public class JDAPFilterGreaterOrEqual extends JDAPFilterAVA {
/**
* Constructs greater or equal filter.
* @param ava attribute value assertion
*/
public JDAPFilterGreaterOrEqual(JDAPAVA ava) {
super(BERTag.CONSTRUCTED|BERTag.CONTEXT|5, ava);
}
/**
* Retrieves the string representation of the filter.
* @return string representation
*/
public String toString() {
return "JDAPFilterGreaterOrEqual {" +
super.getAVA().toString() + "}";
}
}

View File

@@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client;
import java.util.*;
import org.ietf.ldap.ber.stream.*;
import java.io.*;
/**
* This class implements the less or equal filter.
* <pre>
* lessOrEqual [6] AttributeValueAssertion
* </pre>
*
* @version 1.0
*/
public class JDAPFilterLessOrEqual extends JDAPFilterAVA {
/**
* Constructs less or equal filter.
* @param ava attribute value assertion
*/
public JDAPFilterLessOrEqual(JDAPAVA ava) {
super(BERTag.CONSTRUCTED|BERTag.CONTEXT|6, ava);
}
/**
* Retrieves the string representation of the filter.
* @return string representation
*/
public String toString() {
return "JDAPFilterLessOrEqual {" +
super.getAVA().toString() + "}";
}
}

View File

@@ -0,0 +1,70 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client;
import java.util.*;
import org.ietf.ldap.ber.stream.*;
import java.io.*;
/**
* This class implements the filter not.
* <P>See RFC 1777.
*
* <pre>
* not [2] Filter
* </pre>
*
* @version 1.0
*/
public class JDAPFilterNot extends JDAPFilter {
/**
* Internal variables
*/
private JDAPFilter m_filter = null;
/**
* Constructs the filter.
*/
public JDAPFilterNot(JDAPFilter filter) {
super();
m_filter = filter;
}
/**
* Gets ber representation of the filter.
* @return ber representation
*/
public BERElement getBERElement() {
BERTag element = new BERTag(BERTag.CONSTRUCTED|BERTag.CONTEXT|2,
m_filter.getBERElement(), false /* true */);
return element;
}
/**
* Gets string reprensetation of the filter.
* @return string representation
*/
public String toString() {
return "JDAPFilterNot {" + m_filter.toString() + "}";
}
}

View File

@@ -0,0 +1,179 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client;
import java.util.Vector;
import java.io.*;
import org.ietf.ldap.ber.stream.*;
/**
* This class provides miscellaneous operations for JDAPFilter object.
* It converts string with escape characters to the byte array. It also
* returns the ber octet string for the specified string with escape
* characters.
*/
public class JDAPFilterOpers {
private static final String escapeKey = "\\";
private static final boolean m_debug = false;
/**
* Returns the octetString for the given string
* @return The octetString for the given string
*/
static BEROctetString getOctetString(String str) {
if (str.indexOf(escapeKey) >= 0) {
byte[] byteVal = JDAPFilterOpers.getByteValues(str);
return new BEROctetString(byteVal);
}
else
return new BEROctetString(str);
}
/**
* Preprocess the LDAPv2 RFC1960 style filter escape sequences (precede
* a character with a a backslash) and convert them into the
* LDAPv3 style RFC2254 escape sequences (encode a character as a backslash
* followed by the two hex digits representing the character ASCII value).
*
* LDAPv3 style unescaping is done from the getByteValues()method. We must
* process LDAPv2 escaped characters earlier to get rid of possible "\(" \)"
* sequences which would make filter parsing in the JDAPFilter operate incorrectly.
*/
public static String convertLDAPv2Escape(String filter) {
if (filter.indexOf('\\') < 0) {
return filter;
}
StringBuffer sb = new StringBuffer();
int i=0, start=0, len=filter.length();
while(start < len && (i = filter.indexOf('\\', start)) >= 0 ) {
sb.append(filter.substring(start, i+1)); // include also '\'
try {
char c = filter.charAt(i+1);
if ((c >= ' ' && c < 127) && !isHexDigit(c)) {
sb.append(Integer.toHexString(c));
}
else {
sb.append(c);
}
start = i + 2;
}
catch (IndexOutOfBoundsException e) {
throw new IllegalArgumentException("Bad search filter");
}
}
if (start < len) {
sb.append(filter.substring(start));
}
return sb.toString();
}
private static boolean isHexDigit(char c) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
/**
* This method converts the given string into bytes. It also handles
* the escape characters embedded in the given string.
* @param str The given string being converted into a byte array
* @return A byte array
*/
static byte[] getByteValues(String str) {
int pos = 0;
Vector v = new Vector();
String val = new String(str);
int totalSize = 0;
// check if any escape character in the string
while ((pos = val.indexOf(escapeKey)) >= 0) {
String s1 = val.substring(0, pos);
try {
byte[] b = s1.getBytes("UTF8");
totalSize += b.length;
v.addElement(b);
} catch (UnsupportedEncodingException e) {
printDebug(e.toString());
return null;
}
Integer num = null;
// decode this number to integer, exception thrown when this is not the
// hex
try {
String hex = "0x"+val.substring(pos+1, pos+3);
num = Integer.decode(hex);
} catch (IndexOutOfBoundsException e) {
printDebug(e.toString());
throw new IllegalArgumentException("Bad search filter");
} catch (NumberFormatException e) {
printDebug(e.toString());
throw new IllegalArgumentException("Bad search filter");
}
byte[] b = {(byte)num.intValue()};
totalSize += b.length;
v.addElement(b);
// skip an escape and two chars after escape
val = val.substring(pos+3);
}
if (val.length() > 0) {
try {
byte[] b = val.getBytes("UTF8");
totalSize += b.length;
v.addElement(b);
} catch (UnsupportedEncodingException e) {
printDebug(e.toString());
return null;
}
}
byte[] result = new byte[totalSize];
pos = 0;
for (int i=0; i<v.size(); i++) {
byte[] b = (byte[])v.elementAt(i);
System.arraycopy(b, 0, result, pos, b.length);
pos = pos+b.length;
}
return result;
}
/**
* Print debug message
*/
private static void printDebug(String str) {
if (m_debug)
System.out.println(str);
}
}

View File

@@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client;
import java.util.*;
import org.ietf.ldap.ber.stream.*;
import java.io.*;
/**
* This class implements the filter And.
* <P>See RFC 1777.
*
* <pre>
* or [1] SET OF Filter
* </pre>
*
* @version 1.0
*/
public class JDAPFilterOr extends JDAPFilterSet {
/**
* Constructs the filter.
*/
public JDAPFilterOr() {
super(BERTag.CONSTRUCTED|BERTag.CONTEXT|1);
}
/**
* Gets string reprensetation of the filter.
* @return string representation
*/
public String toString() {
return "JDAPFilterOr {" + super.getParamString() + "}";
}
}

View File

@@ -0,0 +1,70 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client;
import java.util.*;
import org.ietf.ldap.ber.stream.*;
import java.io.*;
/**
* This class implements the filter present.
* <P>See RFC 1777.
*
* <pre>
* present [7] AttributeType
* </pre>
*
* @version 1.0
*/
public class JDAPFilterPresent extends JDAPFilter {
/**
* Internal variables
*/
private String m_type = null;
/**
* Constructs the filter.
* @param type attribute type
*/
public JDAPFilterPresent(String type) {
super();
m_type = type;
}
/**
* Gets ber representation of the filter.
* @return ber representation
*/
public BERElement getBERElement() {
BEROctetString s = new BEROctetString(m_type);
BERTag element = new BERTag(BERTag.CONTEXT|7, s, true);
return element;
}
/**
* Gets string reprensetation of the filter.
* @return string representation
*/
public String toString() {
return "JDAPFilterPresent {" + m_type + "}";
}
}

View File

@@ -0,0 +1,89 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client;
import java.util.*;
import org.ietf.ldap.ber.stream.*;
import java.io.*;
/**
* This class implements the base class of filter "and" and filter "or".
*
* @version 1.0
*/
public abstract class JDAPFilterSet extends JDAPFilter {
/**
* Internal variables
*/
private int m_tag;
private Vector m_set = new Vector();
/**
* Constructs the filter set.
* @param tag tag
*/
public JDAPFilterSet(int tag) {
super();
m_tag = tag;
}
/**
* Adds filter into the filter set.
* @param filter adding filter
*/
public void addElement(JDAPFilter filter) {
m_set.addElement(filter);
}
/**
* Gets the ber representation of the filter.
* @return ber representation
*/
public BERElement getBERElement() {
try {
BERSet filters = new BERSet();
for (int i = 0; i < m_set.size(); i++) {
JDAPFilter f = (JDAPFilter)m_set.elementAt(i);
filters.addElement(f.getBERElement());
}
BERTag element = new BERTag(m_tag, filters, true);
return element;
} catch (IOException e) {
return null;
}
}
/**
* Gets the filter set parameters.
* @return set parameters
*/
public String getParamString() {
String s = "";
for (int i = 0; i < m_set.size(); i++) {
if (i != 0)
s = s + ",";
JDAPFilter f = (JDAPFilter)m_set.elementAt(i);
s = s + f.toString();
}
return s;
}
}

View File

@@ -0,0 +1,154 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client;
import java.util.*;
import org.ietf.ldap.ber.stream.*;
import java.io.*;
/**
* This class implements the filter substring.
* <P>See RFC 1777.
*
* <pre>
* [4] SEQUENCE {
* type AttributeType,
* SEQUENCE OF CHOICE {
* initial [0] LDAPString,
* any [1] LDAPString,
* final [2] LDAPString
* }
* }
* </pre>
*
* @version 1.0
*/
public class JDAPFilterSubString extends JDAPFilter {
/**
* Internal variables
*/
private String m_type = null;
private Vector m_initial = new Vector();
private Vector m_any = new Vector();
private Vector m_final = new Vector();
/**
* Constructs the filter.
* @param type attribute type
*/
public JDAPFilterSubString(String type) {
super();
m_type = type;
}
/**
* Adds initial substring.
* @param s initial substring
*/
public void addInitial(String s) {
m_initial.addElement(s);
}
/**
* Adds any substring.
* @param s any substring
*/
public void addAny(String s) {
m_any.addElement(s);
}
/**
* Adds final substring.
* @param s final substring
*/
public void addFinal(String s) {
m_final.addElement(s);
}
/**
* Gets ber representation of the filter.
* @return ber representation
*/
public BERElement getBERElement() {
BERSequence seq = new BERSequence();
seq.addElement(new BEROctetString(m_type));
BERSequence str_seq = new BERSequence();
for (int i = 0; i < m_initial.size(); i++) {
String val = (String)m_initial.elementAt(i);
if (val == null)
continue;
BERTag str = new BERTag(BERTag.CONTEXT|0,
JDAPFilterOpers.getOctetString(val), true);
str_seq.addElement(str);
}
for (int i = 0; i < m_any.size(); i++) {
String val = (String)m_any.elementAt(i);
if (val == null)
continue;
BERTag str = new BERTag(BERTag.CONTEXT|1,
JDAPFilterOpers.getOctetString(val), true);
str_seq.addElement(str);
}
for (int i = 0; i < m_final.size(); i++) {
String val = (String)m_final.elementAt(i);
if (val == null)
continue;
BERTag str = new BERTag(BERTag.CONTEXT|2,
JDAPFilterOpers.getOctetString(val), true);
str_seq.addElement(str);
}
seq.addElement(str_seq);
BERTag element = new BERTag(BERTag.CONSTRUCTED|BERTag.CONTEXT|4,
seq, true);
return element;
}
/**
* Gets string reprensetation of the filter.
* @return string representation
*/
public String toString() {
String initial = "";
for (int i = 0; i < m_initial.size(); i++) {
if (i != 0)
initial = initial + ",";
initial = initial + (String)m_initial.elementAt(i);
}
String any = "";
for (int i = 0; i < m_any.size(); i++) {
if (i != 0)
any = any + ",";
any = any + (String)m_any.elementAt(i);
}
String s_final = "";
for (int i = 0; i < m_final.size(); i++) {
if (i != 0)
s_final = s_final + ",";
s_final = s_final + (String)m_final.elementAt(i);
}
return "JDAPFilterSubString {type=" + m_type + ", initial=" + initial +
", any=" + any + ", final=" + s_final + "}";
}
}

View File

@@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client.opers;
import java.util.*;
import org.ietf.ldap.client.*;
import org.ietf.ldap.ber.stream.*;
import java.io.*;
import java.net.*;
/**
* This class implements the abandon request. This object
* is sent to the ldap server.
* <P>See RFC 1777.
*
* <pre>
* AbandonRequest ::= [APPLICATION 16] MessageID
* </pre>
*
* @version 1.0
*/
public class JDAPAbandonRequest implements JDAPProtocolOp {
/**
* Internal variables
*/
protected int m_msgid;
/**
* Constructs abandon request.
* @param msgid message identifier
*/
public JDAPAbandonRequest(int msgid) {
m_msgid = msgid;
}
/**
* Retrieves the protocol operation type.
* @return protocol type
*/
public int getType() {
return JDAPProtocolOp.ABANDON_REQUEST;
}
/**
* Gets the ber representation of abandon request.
* @return ber representation of request
*/
public BERElement getBERElement() {
/* Assumed m_msgid = 1. The BER encoding output
* should be
*
* [*] umich-ldap-v3.3:
* 0x50 (implicit tagged integer)
* 0x01 (length)
* 0x01 (message id)
*/
BERInteger i = new BERInteger(m_msgid);
BERTag element = new BERTag(BERTag.APPLICATION|16, i, true);
return element;
}
/**
* Retrieves the string representation of abandon request.
* @return string representation
*/
public String toString() {
return "AbandonRequest {msgid=" + m_msgid + "}";
}
}

View File

@@ -0,0 +1,146 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client.opers;
import java.util.*;
import org.ietf.ldap.*;
import org.ietf.ldap.client.*;
import org.ietf.ldap.ber.stream.*;
import java.io.*;
/**
* This class implements the add request. This object
* is sent to the ldap server.
* <P>See RFC 1777.
*
* <pre>
* AddRequest ::= [APPLICATION 8] SEQUENCE {
* entry LDAPDN,
* attrs SEQUENCE OF SEQUENCE {
* type AttributeType,
* values SET OF AttributeValue
* }
* }
* </pre>
*
* @version 1.0
*/
public class JDAPAddRequest extends JDAPBaseDNRequest
implements JDAPProtocolOp {
/**
* Internal variables
*/
protected String m_dn = null;
protected LDAPAttribute m_attrs[] = null;
/**
* Constructs add request.
* @param dn distinguished name of adding entry
* @param attrs list of attribute associated with entry
*/
public JDAPAddRequest(String dn, LDAPAttribute attrs[]) {
m_dn = dn;
m_attrs = attrs;
}
/**
* Retrieves protocol operation type.
* @return protcol type
*/
public int getType() {
return JDAPProtocolOp.ADD_REQUEST;
}
/**
* Sets the base dn component.
* @param basedn base dn
*/
public void setBaseDN(String basedn) {
m_dn = basedn;
}
/**
* Gets the base dn component.
* @return base dn
*/
public String getBaseDN() {
return m_dn;
}
/**
* Gets the ber representation of add request.
* @return ber representation of request
*/
public BERElement getBERElement() {
/* Assumed that adding cn=patrick,o=ncware,c=ca with
* following attributes:
* cn: patrick
* title: programmer
* [*] umich-ldap-v3.3:
* 0x68 0x46 ([APPLICATION8])
* 0x04 0x1a c n = p a t r i c k , 0x20
* o = n c w a r e , 0x20 c =
* c a (entry - OctetString)
* 0x30 0x28 (SEQUENCE)
* 0x30 0x0f (SEQUENCE)
* 0x04 0x02 c n (attribute type - OctetString)
* 0x31 0x09 (SET OF)
* 0x04 0x07 p a t r i c k (attribute value - OctetString)
* 0x30 0x15
* 0x04 0x05 t i t l e
* 0x31 0x0c (SET OF)
* 0x04 0x0a p r o g r a m m e r
*/
BERSequence seq = new BERSequence();
seq.addElement(new BEROctetString (m_dn));
BERSequence attrs_list = new BERSequence();
for (int i = 0; i < m_attrs.length; i++) {
attrs_list.addElement(m_attrs[i].getBERElement());
}
seq.addElement(attrs_list);
BERTag element = new BERTag(BERTag.APPLICATION|BERTag.CONSTRUCTED|8,
seq, true);
return element;
}
/**
* Retrieves the string representation of add request parameters.
* @return string representation of add request parameters
*/
public String getParamString() {
String s = "";
for (int i = 0; i < m_attrs.length; i++) {
if (i != 0)
s = s + " ";
s = s + m_attrs[i].toString();
}
return "{entry='" + m_dn + "', attrs='" + s + "'}";
}
/**
* Retrieves the string representation of add request.
* @return string representation of add request
*/
public String toString() {
return "AddRequest " + getParamString();
}
}

View File

@@ -0,0 +1,65 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client.opers;
import java.util.*;
import org.ietf.ldap.client.*;
import org.ietf.ldap.ber.stream.*;
import java.io.*;
import java.net.*;
/**
* This class implements the add response. This object
* is sent from the ldap server to the interface.
* <P>See RFC 1777.
*
* <pre>
* AddResponse ::= [APPLICATION 9] LDAPResult
* </pre>
*
* @version 1.0
*/
public class JDAPAddResponse extends JDAPResult implements JDAPProtocolOp {
/**
* Constructs add response.
* @param element ber element of add response
*/
public JDAPAddResponse(BERElement element) throws IOException {
super(((BERTag)element).getValue());
}
/**
* Retrieves the protocol operation type.
* @return protocol type
*/
public int getType() {
return JDAPProtocolOp.ADD_RESPONSE;
}
/**
* Retrieve the string representation.
* @return string representation
*/
public String toString() {
return "AddResponse " + super.getParamString();
}
}

View File

@@ -0,0 +1,50 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
package org.ietf.ldap.client.opers;
import java.util.*;
import org.ietf.ldap.client.*;
import org.ietf.ldap.ber.stream.*;
import java.io.*;
import java.net.*;
/**
* This is the base class for all the request that
* has a base dn component. The existence of this
* class is due to the JDAPReferralThread.
*
* @version 1.0
*/
public abstract class JDAPBaseDNRequest {
/**
* Sets the base dn component in the request.
* @param basedn base DN
*/
public abstract void setBaseDN(String basedn);
/**
* Gets the base dn component in the request.
* @return base dn
*/
public abstract String getBaseDN();
}

Some files were not shown because too many files have changed in this diff Show More