Compare commits

..

12 Commits

Author SHA1 Message Date
miodrag%netscape.com
3a126fe6fc More updates
git-svn-id: svn://10.0.0.236/branches/LDAPJavaSDK_40beta_19990802_BRANCH@42076 18797224-902f-48f8-a5cc-f745e15eee43
1999-08-04 01:44:42 +00:00
miodrag%netscape.com
bf76134755 doc path change
git-svn-id: svn://10.0.0.236/branches/LDAPJavaSDK_40beta_19990802_BRANCH@42072 18797224-902f-48f8-a5cc-f745e15eee43
1999-08-04 00:46:51 +00:00
miodrag%netscape.com
677ac0508a Renamed
git-svn-id: svn://10.0.0.236/branches/LDAPJavaSDK_40beta_19990802_BRANCH@42071 18797224-902f-48f8-a5cc-f745e15eee43
1999-08-04 00:27:56 +00:00
miodrag%netscape.com
948f53fd8c Added doc target
git-svn-id: svn://10.0.0.236/branches/LDAPJavaSDK_40beta_19990802_BRANCH@42069 18797224-902f-48f8-a5cc-f745e15eee43
1999-08-04 00:14:57 +00:00
miodrag%netscape.com
d643bfb551 Update for javadoc and jdk version
git-svn-id: svn://10.0.0.236/branches/LDAPJavaSDK_40beta_19990802_BRANCH@42067 18797224-902f-48f8-a5cc-f745e15eee43
1999-08-04 00:03:24 +00:00
miodrag%netscape.com
31c81ab0b0 Renamed
git-svn-id: svn://10.0.0.236/branches/LDAPJavaSDK_40beta_19990802_BRANCH@41987 18797224-902f-48f8-a5cc-f745e15eee43
1999-08-03 15:50:51 +00:00
miodrag%netscape.com
84b616c6f4 Links fixed
git-svn-id: svn://10.0.0.236/branches/LDAPJavaSDK_40beta_19990802_BRANCH@41962 18797224-902f-48f8-a5cc-f745e15eee43
1999-08-03 07:27:06 +00:00
miodrag%netscape.com
25df3ce15f Update
git-svn-id: svn://10.0.0.236/branches/LDAPJavaSDK_40beta_19990802_BRANCH@41961 18797224-902f-48f8-a5cc-f745e15eee43
1999-08-03 07:23:15 +00:00
miodrag%netscape.com
aa4f4a38ba Release nites for 4.0 beta
git-svn-id: svn://10.0.0.236/branches/LDAPJavaSDK_40beta_19990802_BRANCH@41957 18797224-902f-48f8-a5cc-f745e15eee43
1999-08-03 07:14:11 +00:00
miodrag%netscape.com
c98fd85075 Update for 4.0 beta
git-svn-id: svn://10.0.0.236/branches/LDAPJavaSDK_40beta_19990802_BRANCH@41953 18797224-902f-48f8-a5cc-f745e15eee43
1999-08-03 06:39:16 +00:00
miodrag%netscape.com
9ac2abf404 Updates for 4.0 beta
git-svn-id: svn://10.0.0.236/branches/LDAPJavaSDK_40beta_19990802_BRANCH@41951 18797224-902f-48f8-a5cc-f745e15eee43
1999-08-03 06:23:52 +00:00
(no author)
35717268e5 This commit was manufactured by cvs2svn to create branch
'LDAPJavaSDK_40beta_19990802_BRANCH'.

git-svn-id: svn://10.0.0.236/branches/LDAPJavaSDK_40beta_19990802_BRANCH@33891 18797224-902f-48f8-a5cc-f745e15eee43
1999-06-05 01:14:52 +00:00
260 changed files with 48257 additions and 8833 deletions

View File

@@ -1,132 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* 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 the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
This file overrides all option settings in the IDE. It is an attempt to allow all builds
to have the same options.
Note: We can't use ConditionalMacros.h in this file because it will conflict with
the PowerPlant precompiled headers.
*/
/* warning pragmas */
#pragma warn_hidevirtual on
#pragma warn_emptydecl on
#pragma warn_unusedvar on
#pragma warn_extracomma on
#pragma warn_illpragma on
#pragma warn_possunwant on
#pragma warn_unusedarg off /* turned off to reduce warnings */
#pragma check_header_flags on
/* Language features that must be the same across libraries... */
#pragma enumsalwaysint on
#pragma unsigned_char off
#pragma exceptions on
#pragma bool on
#pragma wchar_type on
#pragma RTTI on
/* Save as much space as possible with strings... */
#pragma pool_strings on
#pragma dont_reuse_strings off
#pragma options align=native
#pragma sym on /* Takes no memory. OK in non-debug. */
#ifdef powerc /* ...generating PowerPC */
#pragma toc_data on
#pragma fp_contract on
#pragma readonly_strings on
#ifdef DEBUG
#pragma profile off /* Turn this on to profile the application. */
/* Look for more details about profiling in nsMacMessagePump.cpp. */
#pragma traceback on
#pragma global_optimizer off
#pragma scheduling off
#pragma peephole off
#pragma optimize_for_size off
#else
#if TARGET_CARBON
#pragma traceback on /* should always be ON for Carbon builds */
#else
#pragma traceback off /* leave on until the final release, so MacsBug logs are interpretable */
#endif
#pragma global_optimizer on
#pragma optimization_level 4
#pragma scheduling 603
#pragma peephole on
#pragma optimize_for_size on
#pragma opt_strength_reduction on
#pragma opt_propagation on
#pragma opt_loop_invariants on
#pragma opt_lifetimes on
#pragma opt_dead_code on
#pragma opt_dead_assignments on
#pragma opt_common_subs on
#endif
#else /* ...generating 68k */
#pragma code68020 on
#pragma code68881 off
/* Far everything... */
#pragma far_code
#pragma far_data on
#pragma far_strings on
#pragma far_vtables on
#pragma fourbyteints on /* 4-byte ints */
#pragma IEEEdoubles on /* 8-byte doubles (as required by Java and NSPR) */
#ifdef DEBUG
#pragma macsbug on
#pragma oldstyle_symbols off
#else
#pragma macsbug off
#endif
#endif

View File

@@ -1,5 +0,0 @@
#
# This is a list of local files which get copied to the mozilla:dist directory
#
IDE_Options.h

View File

@@ -1,59 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* 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 the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#error "DonÕt use me!"
#define OLDROUTINELOCATIONS 0
#define XP_MAC 1
#define NSPR20 1
#define _NO_FAST_STRING_INLINES_ 1
#define HAVE_BOOLEAN 1
#define NETSCAPE 1
#define OTUNIXERRORS 1 /* We want OpenTransport error codes */
#define OJI 1
/*
This compiles in heap dumping utilities and other good stuff
for developers -- maybe we only want it in for a special SDK
nspr/java runtime(?):
*/
#define DEVELOPER_DEBUG 1
#define MAX(_a,_b) ((_a) < (_b) ? (_b) : (_a))
#define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))

Binary file not shown.

View File

@@ -1,80 +0,0 @@
#!perl
#
# 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) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
# Simon Fraser <sfraser@netscape.com>
#
require 5.004;
use strict;
use Cwd;
use Moz::BuildUtils;
use Moz::BuildCore;
#-------------------------------------------------------------
# Where have the build options gone?
#
# The various build flags have been centralized into one place.
# The master list of options is in MozBuildFlags.txt. However,
# you should never need to edit that file, or this one.
#
# To customize what gets built, or where to start the build,
# edit the $prefs_file_name file in
# System Folder:Preferences:Mozilla build prefs:
# Documentation is provided in that file.
#-------------------------------------------------------------
my($prefs_file_name) = "Mozilla opt build prefs";
my($config_header_file_name) = ":mozilla:config:mac:DefinesOptions.h";
#-------------------------------------------------------------
# hashes to hold build options
#-------------------------------------------------------------
my(%build);
my(%options);
my(%filepaths);
my(%optiondefines);
# Hash of input files for this build. Eventually, there will be
# input files for manifests, and projects too.
my(%inputfiles) = (
"buildflags", "MozillaBuildFlags.txt",
"checkoutdata", "MozillaCheckoutList.txt",
"buildprogress", "¥ Mozilla opt progress",
"buildmodule", "MozillaBuildList.pm",
"checkouttime", "Mozilla last checkout"
);
#-------------------------------------------------------------
# end build hashes
#-------------------------------------------------------------
# set the build root directory, which is the the dir above mozilla
SetupBuildRootDir(":mozilla:build:mac:build_scripts");
# Set up all the flags on $main::, like DEBUG, CARBON etc.
# Override the defaults using the preferences files.
SetupDefaultBuildOptions(0, ":mozilla:dist:viewer:", $config_header_file_name);
my($do_checkout) = 0;
my($do_build) = 1;
RunBuild($do_checkout, $do_build, \%inputfiles, $prefs_file_name);

View File

@@ -1,80 +0,0 @@
#!perl
#
# 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) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
# Simon Fraser <sfraser@netscape.com>
#
require 5.004;
use strict;
use Cwd;
use Moz::BuildUtils;
use Moz::BuildCore;
#-------------------------------------------------------------
# Where have the build options gone?
#
# The various build flags have been centralized into one place.
# The master list of options is in MozBuildFlags.txt. However,
# you should never need to edit that file, or this one.
#
# To customize what gets built, or where to start the build,
# edit the $prefs_file_name file in
# System Folder:Preferences:Mozilla build prefs:
# Documentation is provided in that file.
#-------------------------------------------------------------
my($prefs_file_name) = "Mozilla debug build prefs";
my($config_header_file_name) = ":mozilla:config:mac:DefinesOptionsDebug.h";
#-------------------------------------------------------------
# hashes to hold build options
#-------------------------------------------------------------
my(%build);
my(%options);
my(%filepaths);
my(%optiondefines);
# Hash of input files for this build. Eventually, there will be
# input files for manifests, and projects too.
my(%inputfiles) = (
"buildflags", "MozillaBuildFlags.txt",
"checkoutdata", "MozillaCheckoutList.txt",
"buildprogress", "¥ Mozilla debug progress",
"buildmodule", "MozillaBuildList.pm",
"checkouttime", "Mozilla last checkout"
);
#-------------------------------------------------------------
# end build hashes
#-------------------------------------------------------------
# set the build root directory, which is the the dir above mozilla
SetupBuildRootDir(":mozilla:build:mac:build_scripts");
# Set up all the flags on $main::, like DEBUG, CARBON etc.
# Override the defaults using the preferences files.
SetupDefaultBuildOptions(1, ":mozilla:dist:viewer_debug:", $config_header_file_name);
my($do_pull) = 0; # overridden by flags and prefs
my($do_build) = 1;
RunBuild($do_pull, $do_build, \%inputfiles, $prefs_file_name);

View File

@@ -1,595 +0,0 @@
#!perl -w
package Moz::BuildCore;
require 5.004;
require Exporter;
use strict;
use vars qw( @ISA @EXPORT );
# perl includes
use Cwd;
use POSIX;
use Time::Local;
use File::Basename;
use LWP::Simple;
# homegrown
use Moz::Moz;
use Moz::Jar;
use Moz::BuildFlags;
use Moz::BuildUtils;
use Moz::CodeWarriorLib;
# use MozillaBuildList; # eventually, this should go away, and be replaced by data input
@ISA = qw(Exporter);
@EXPORT = qw(
RunBuild
);
#//--------------------------------------------------------------------------------------------------
#// DoPrebuildCheck
#//
#// Check the build tools etc before running the build.
#//--------------------------------------------------------------------------------------------------
sub DoPrebuildCheck()
{
SanityCheckBuildOptions();
# launch codewarrior and persist its location. Have to call this before first
# call to getCodeWarriorPath().
my($ide_path_file) = $main::filepaths{"idepath"};
$ide_path_file = full_path_to($ide_path_file);
LaunchCodeWarrior($ide_path_file);
}
#//--------------------------------------------------------------------------------------------------
#// SanityCheckBuildOptions
#//--------------------------------------------------------------------------------------------------
sub SanityCheckBuildOptions()
{
my($bad_options) = 0;
# Jar options
if (!$main::options{chrome_jars} && !$main::options{chrome_files})
{
print "Warning: Both \$options{chrome_jars} and \$options{chrome_files} are off. You won't get any chrome.\n";
$bad_options = 1;
}
if (!$main::options{chrome_jars} && $main::options{use_jars})
{
print "Warning: \$options{chrome_jars} is off but \$options{use_jars} is on. Your build won't run (expects jars, got files).\n";
$bad_options = 1;
}
if (!$main::options{chrome_files} && !$main::options{use_jars})
{
print "Warning: \$options{chrome_jars} is off but \$options{chrome_files} is on. Your build won't run (expects files, got jars).\n";
$bad_options = 1;
}
if ($main::options{ldap_experimental} && !$main::options{ldap})
{
print "Warning: \$options{ldap_experimental} is on but \$options{ldap} is off. LDAP experimental features will not be built.\n";
$bad_options = 1;
}
if ($main::options{wsp} && !$main::options{xmlextras})
{
print "Warning: \$options{wsp} is on but \$options{xmlextras} is off. wsp will not be built.\n";
$bad_options = 1;
}
if ($bad_options) {
print "Build will start in 5 seconds. Press command-. to stop\n";
DelayFor(5);
}
}
#//--------------------------------------------------------------------------------------------------
#// GenBuildSystemInfo
#//--------------------------------------------------------------------------------------------------
sub GenBuildSystemInfo()
{
# always rebuild the configuration program.
BuildProjectClean(":mozilla:build:mac:tools:BuildSystemInfo:BuildSystemInfo.mcp", "BuildSystemInfo");
# delete the configuration file.
unlink(":mozilla:build:mac:BuildSystemInfo.pm");
# run the program.
system(":mozilla:build:mac:BuildSystemInfo");
# wait for the file to be created.
while (!(-e ":mozilla:build:mac:BuildSystemInfo.pm")) { WaitNextEvent(); }
# wait for BuildSystemInfo to finish, so that we see correct results.
while (IsProcessRunning("BuildSystemInfo")) { WaitNextEvent(); }
# now, evaluate the contents of the file.
open(F, ":mozilla:build:mac:BuildSystemInfo.pm");
while (<F>) { eval; }
close(F);
}
#//--------------------------------------------------------------------------------------------------
#// Make library aliases
#//--------------------------------------------------------------------------------------------------
sub MakeLibAliases()
{
my($dist_dir) = GetBinDirectory();
#// ProfilerLib
if ($main::PROFILE)
{
my($profilerlibpath) = Moz::CodeWarriorLib::getCodeWarriorPath("MacOS Support:Profiler:Profiler Common:ProfilerLib");
MakeAlias("$profilerlibpath", "$dist_dir"."Essential Files:");
}
}
#//--------------------------------------------------------------------------------------------------
#// ConfigureBuildSystem
#//
#// defines some build-system configuration variables.
#//--------------------------------------------------------------------------------------------------
sub ConfigureBuildSystem()
{
#// In the future, we may want to do configurations based on the actual build system itself.
#// GenBuildSystemInfo();
#// For now, if we discover a newer header file than existed in Universal Interfaces 3.2,
#// we'll assume that 3.3 or later is in use.
my($universal_interfaces) = Moz::CodeWarriorLib::getCodeWarriorPath("MacOS Support:Universal:Interfaces:CIncludes:");
if (-e ($universal_interfaces . "ControlDefinitions.h")) {
$main::UNIVERSAL_INTERFACES_VERSION = 0x0330;
}
#// Rename IC SDK folder in the Mac OS Support folder
my($ic_sdk_folder) = Moz::CodeWarriorLib::getCodeWarriorPath("MacOS Support:ICProgKit2.0.2");
if( -e $ic_sdk_folder)
{
my($new_ic_folder_name) = Moz::CodeWarriorLib::getCodeWarriorPath("MacOS Support:(ICProgKit2.0.2)");
rename ($ic_sdk_folder, $new_ic_folder_name);
# note that CodeWarrior doesn't descend into folders with () the name
print "Mozilla no longer needs the Internet Config SDK to build:\n Renaming the 'ICProgKit2.0.2' folder to '(ICProgKit2.0.2)'\n";
}
printf("UNIVERSAL_INTERFACES_VERSION = 0x%04X\n", $main::UNIVERSAL_INTERFACES_VERSION);
# alias required CodeWarrior libs into the Essential Files folder (only the Profiler lib now)
MakeLibAliases();
}
#//--------------------------------------------------------------------------------------------------
#// CheckOutModule. Takes variable number of args; first two are required
#//--------------------------------------------------------------------------------------------------
sub CheckOutModule($$$$)
{
my($session, $module, $revision, $date) = @_;
my($result) = $session->checkout($module, $revision, $date);
# result of 1 is success
if ($result) { return; }
my($checkout_err) = $session->getLastError();
if ($checkout_err == 708) {
die "Error: Checkout was cancelled.\n";
} elsif ($checkout_err == 911) {
die "Error: CVS session settings are incorrect. Check your password, and the CVS root settings.\n";
} elsif ($checkout_err == 703) {
die "Error: CVS checkout failed. Unknown module, unknown tag, bad username, or other CVS error.\n";
} elsif ($checkout_err == 711) {
print "Checkout of '$module' failed.\n";
}
}
#//--------------------------------------------------------------------------------------------------
#// getScriptFolder
#//--------------------------------------------------------------------------------------------------
sub getScriptFolder()
{
return dirname($0);
}
#//--------------------------------------------------------------------------------------------------
#// getScriptFolder
#//--------------------------------------------------------------------------------------------------
sub get_url_contents($)
{
my($url) = @_;
my($url_contents) = LWP::Simple::get($url);
$url_contents =~ s/\r\n/\n/g; # normalize linebreaks
$url_contents =~ s/\r/\n/g; # normalize linebreaks
return $url_contents;
}
#//--------------------------------------------------------------------------------------------------
#// get_files_from_content
#//--------------------------------------------------------------------------------------------------
sub uniq
{
my $lastval;
grep(($_ ne $lastval, $lastval = $_)[$[], @_);
}
#//--------------------------------------------------------------------------------------------------
#// get_files_from_content
#//--------------------------------------------------------------------------------------------------
sub get_files_from_content($)
{
my($content) = @_;
my(@jscalls) = grep (/return js_file_menu[^{]*/, split(/\n/, $content));
my $i;
for ($i = 0; $i < @jscalls ; $i++)
{
$jscalls[$i] =~ s/.*\(|\).*//g;
my(@callparams) = split(/,/, $jscalls[$i]);
my ($repos, $dir, $file, $rev) = grep(s/['\s]//g, @callparams);
$jscalls[$i] = "$dir/$file";
}
&uniq(sort(@jscalls));
}
#//--------------------------------------------------------------------------------------------------
#// getLastUpdateTime
#//
#// Get the last time we updated. Return 0 on failure
#//--------------------------------------------------------------------------------------------------
sub getLastUpdateTime($)
{
my($timestamp_file) = @_;
my($time_string);
local(*TIMESTAMP_FILE);
unless (open(TIMESTAMP_FILE, "< $timestamp_file")) { return 0; }
while (<TIMESTAMP_FILE>)
{
my($line) = $_;
chomp($line);
# ignore comments and empty lines
if ($line =~ /^\#/ || $line =~ /^\s*$/) {
next;
}
$time_string = $line;
}
# get the epoch seconds
my($last_update_secs) = $time_string;
$last_update_secs =~ s/\s#.+$//;
print "FAST_UPDATE found that you last updated at ".localtime($last_update_secs)."\n";
# how long ago was this, in hours?
my($gm_now) = time();
my($update_hours) = 1 + ceil(($gm_now - $last_update_secs) / (60 * 60));
return $update_hours;
}
#//--------------------------------------------------------------------------------------------------
#// saveCheckoutTimestamp
#//
#// Create a file on disk containing the current time. Param is time(), which is an Epoch seconds
#// (and therefore in GMT).
#//
#//--------------------------------------------------------------------------------------------------
sub saveCheckoutTimestamp($$)
{
my($gm_secs, $timestamp_file) = @_;
local(*TIMESTAMP_FILE);
open(TIMESTAMP_FILE, ">$timestamp_file") || die "Failed to open $timestamp_file\n";
print(TIMESTAMP_FILE "# time of last checkout or update, in GMT. Used by FAST_UPDATE\n");
print(TIMESTAMP_FILE "$gm_secs \# around ".localtime()." local time\n");
close(TIMESTAMP_FILE);
}
#//--------------------------------------------------------------------------------------------------
#// FastUpdate
#//
#// Use Bonsai url data to update only those dirs which have new files
#//
#//--------------------------------------------------------------------------------------------------
sub FastUpdate($$)
{
my($modules, $timestamp_file) = @_; # list of modules to check out
my($num_hours) = getLastUpdateTime($timestamp_file);
if ($num_hours == 0 || $num_hours > 170) {
print "Can't fast_update; last update was too long ago, or never. Doing normal checkout.\n";
return 0;
}
print "Doing fast update, pulling files changed in the last $num_hours hours\n";
my($cvsfile) = AskAndPersistFile($main::filepaths{"sessionpath"});
my($session) = Moz::MacCVS->new( $cvsfile );
unless (defined($session)) { die "Error: Checkout aborted. Cannot create session file: $session" }
# activate MacCVS
ActivateApplication('Mcvs');
my($checkout_start_time) = time();
#print "Time now is $checkout_start_time ($checkout_start_time + 0)\n";
my($this_co);
foreach $this_co (@$modules)
{
my($module, $revision, $date) = ($this_co->[0], $this_co->[1], $this_co->[2]);
# assume that things pulled by date wont change
if ($date ne "") {
print "$module is pulled by date, so ignoring in FastUpdate.\n";
next;
}
my($search_type) = "hours";
my($min_date) = "";
my($max_date) = "";
my($url) = "http://bonsai.mozilla.org/cvsquery.cgi?treeid=default&module=${module}&branch=${revision}&branchtype=match&dir=&file=&filetype=match&who=&whotype=match&sortby=Date&hours=${num_hours}&date=${search_type}&mindate=${min_date}&maxdate=${max_date}&cvsroot=%2Fcvsroot";
if ($revision eq "") {
print "Getting list of checkins to $module from Bonsai...\n";
} else {
print "Getting list of checkins to $module on branch $revision from Bonsai...\n";
}
my(@files) = &get_files_from_content(&get_url_contents($url));
if ($#files > 0)
{
my(@cvs_co_list);
my($co_file);
foreach $co_file (@files)
{
print "Updating $co_file\n";
push(@cvs_co_list, $co_file);
}
my($result) = $session->update($revision, \@cvs_co_list);
# result of 1 is success
if (!$result) { die "Error: Fast update failed\n"; }
} else {
print "No files in this module changed\n";
}
}
saveCheckoutTimestamp($checkout_start_time, $timestamp_file);
return 1;
}
#//--------------------------------------------------------------------------------------------------
#// Checkout
#//--------------------------------------------------------------------------------------------------
sub CheckoutModules($$$)
{
my($modules, $pull_date, $timestamp_file) = @_; # list of modules to check out
my($start_time) = TimeStart();
# assertRightDirectory();
my($cvsfile) = AskAndPersistFile($main::filepaths{"sessionpath"});
my($session) = Moz::MacCVS->new( $cvsfile );
unless (defined($session)) { die "Error: Checkout aborted. Cannot create session file: $session" }
my($checkout_start_time) = time();
# activate MacCVS
ActivateApplication('Mcvs');
my($this_co);
foreach $this_co (@$modules)
{
my($module, $revision, $date) = ($this_co->[0], $this_co->[1], $this_co->[2]);
if ($date eq "") {
$date = $pull_date;
}
CheckOutModule($session, $module, $revision, $date);
# print "Checking out $module with ref $revision, date $date\n";
}
saveCheckoutTimestamp($checkout_start_time, $timestamp_file);
TimeEnd($start_time, "Checkout");
}
#//--------------------------------------------------------------------------------------------------
#// ReadCheckoutModulesFile
#//--------------------------------------------------------------------------------------------------
sub ReadCheckoutModulesFile($$)
{
my($modules_file, $co_list) = @_;
my($checkout_file) = getScriptFolder().":".$modules_file;
local(*CHECKOUT_FILE);
open(CHECKOUT_FILE, "< $checkout_file") || die "Error: failed to open checkout list $checkout_file\n";
while (<CHECKOUT_FILE>)
{
my($line) = $_;
chomp($line);
# ignore comments and empty lines
if ($line =~ /^\#/ || $line =~ /^\s*$/) {
next;
}
my(@cvs_co) = ["", "", ""];
my($module, $revision, $date) = (0, 1, 2);
if ($line =~ /\s*([^#,\s]+)\s*\,\s*([^#,\s]+)\s*\,\s*([^#]+)/)
{
@cvs_co[$module] = $1;
@cvs_co[$revision] = $2;
@cvs_co[$date] = $3;
}
elsif ($line =~ /\s*([^#,\s]+)\s*\,\s*([^#,\s]+)\s*(#.+)?/)
{
@cvs_co[$module] = $1;
@cvs_co[$revision] = $2;
}
elsif ($line =~ /\s*([^#,\s]+)\s*\,\s*,\s*([^#,]+)/)
{
@cvs_co[$module] = $1;
@cvs_co[$date] = $2;
}
elsif ($line =~ /\s*([^#,\s]+)/)
{
@cvs_co[$module] = $1;
}
else
{
die "Error: unrecognized line '$line' in $modules_file\n";
}
# strip surrounding space from date
@cvs_co[$date] =~ s/^\s*|\s*$//g;
# print "Going to check out '@cvs_co[$module]', '@cvs_co[$revision]', '@cvs_co[$date]'\n";
push(@$co_list, \@cvs_co);
}
close(CHECKOUT_FILE);
}
#//--------------------------------------------------------------------------------------------------
#// PullFromCVS
#//--------------------------------------------------------------------------------------------------
sub PullFromCVS($$)
{
unless ( $main::build{pull} ) { return; }
my($modules_file, $timestamp_file) = @_;
StartBuildModule("pull");
my(@cvs_co_list);
ReadCheckoutModulesFile($modules_file, \@cvs_co_list);
if ($main::FAST_UPDATE && $main::options{pull_by_date})
{
die "Error: you can't use FAST_UPDATE if you are pulling by date.\n";
}
my($did_fast_update) = $main::FAST_UPDATE && FastUpdate(\@cvs_co_list, $timestamp_file);
if (!$did_fast_update)
{
my($pull_date) = "";
if ($main::options{pull_by_date})
{
# acceptable CVS date formats are (in local time):
# ISO8601 (e.g. "1972-09-24 20:05") and Internet (e.g. "24 Sep 1972 20:05").
# Perl's localtime() string format also seems to work.
$pull_date = localtime().""; # force string interp.
print "Pulling by date $pull_date\n";
}
CheckoutModules(\@cvs_co_list, $pull_date, $timestamp_file);
}
EndBuildModule("pull");
}
#//--------------------------------------------------------------------------------------------------
#// RunBuild
#//--------------------------------------------------------------------------------------------------
sub RunBuild($$$$)
{
my($do_pull, $do_build, $input_files, $build_prefs) = @_;
InitBuildProgress($input_files->{"buildprogress"});
# if we are pulling, we probably want to do a full build, so clear the build progress
if ($do_pull) {
ClearBuildProgress();
}
# read local prefs, and the build progress file, and set flags to say what to build
SetupBuildParams(\%main::build,
\%main::options,
\%main::optiondefines,
\%main::filepaths,
$input_files->{"buildflags"},
$build_prefs);
# If we were told to pull, make sure we do, overriding prefs etc.
if ($do_pull)
{
$main::build{"pull"} = 1;
}
# transfer this flag
$CodeWarriorLib::CLOSE_PROJECTS_FIRST = $main::CLOSE_PROJECTS_FIRST;
# setup the build log
SetupBuildLog($main::filepaths{"buildlogfilepath"}, $main::USE_TIMESTAMPED_LOGS);
StopForErrors();
if ($main::LOG_TO_FILE) {
RedirectOutputToFile($main::filepaths{"scriptlogfilepath"});
}
# run a pre-build check to see that the tools etc are in order
DoPrebuildCheck();
# do the pull
PullFromCVS($input_files->{"checkoutdata"}, $input_files->{"checkouttime"});
unless ($do_build) { return; }
my($build_start) = TimeStart();
# check the build environment
ConfigureBuildSystem();
# here we load and call methods in the build module indirectly.
# we have to use indirection because the build module can be named
# differently for different builds.
chdir(dirname($0)); # change to the script dir
my($build_module) = $input_files->{"buildmodule"};
# load the build module
require $build_module;
{ # scope for no strict 'refs'
no strict 'refs';
my($package_name) = $build_module;
$package_name =~ s/\.pm$//;
chdir($main::MOZ_SRC);
&{$package_name."::BuildDist"}();
chdir($main::MOZ_SRC);
&{$package_name."::BuildProjects"}();
}
# the build finished, so clear the build progress state
ClearBuildProgress();
TimeEnd($build_start, "Build");
print "Build complete\n";
}
1;

View File

@@ -1,425 +0,0 @@
#!perl -w
package Moz::BuildFlags;
require 5.004;
require Exporter;
# Package that attempts to read a file from the Preferences folder,
# and get build settings out of it
use strict;
use Exporter;
use Cwd;
use File::Basename;
use Moz::Moz;
use Moz::Prefs;
use vars qw(@ISA @EXPORT);
@ISA = qw(Exporter);
@EXPORT = qw(
SetupBuildParams
InitBuildProgress
WriteBuildProgress
ClearBuildProgress
ReadBuildProgress
);
my(@build_flags);
my(@options_flags);
my(@filepath_flags);
my(%arrays_list) = (
"build_flags", \@build_flags,
"options_flags", \@options_flags,
"filepath_flags", \@filepath_flags
);
my($progress_file) = "¥ÊBuild progress";
#-------------------------------------------------------------------------------
# appendArrayFlag
#
# Set a flag in the array
#-------------------------------------------------------------------------------
sub appendArrayFlag(@)
{
my($array_name) = shift;
my($setting) = shift;
my($value) = shift;
my(@optional_values);
foreach (@_) {
push(@optional_values, $_);
}
my(@this_flag) = [$setting, $value, @optional_values];
my($flags_array) = $arrays_list{$array_name};
if ($flags_array)
{
push(@{$flags_array}, @this_flag) || die "Failed to append\n";
}
else
{
die "Error: unknown build flags array $array_name\n";
}
}
#-------------------------------------------------------------------------------
# readFlagsFile
#
# Read the file of build flags from disk. File path is relative to the
# script directory.
#-------------------------------------------------------------------------------
sub readFlagsFile($)
{
my($flags_file) = @_;
my($file_path) = $0;
$file_path =~ s/[^:]+$/$flags_file/;
print "Reading build flags from '$file_path'\n";
local(*FLAGS_FILE);
open(FLAGS_FILE, "< $file_path") || die "Error: failed to open flags file $file_path\n";
my($cur_array) = "";
while(<FLAGS_FILE>)
{
my($line) = $_;
chomp($line);
# ignore comments and empty lines
if ($line =~ /^\#/ || $line =~ /^\s*$/) {
next;
}
# 1-word line, probably array name
if ($line =~ /^([^#\s]+)\s*$/)
{
$cur_array = $1;
next;
}
elsif ($line =~ /^([^#\s]+)\s+\"(.+)\"(\s+#.+)?$/) # quoted option, possible comment
{
my($flag) = $1;
my($setting) = $2;
appendArrayFlag($cur_array, $flag, $setting);
}
elsif ($line =~ /^([^#\s]+)((\s+[^#\s]+)+)(\s+#.+)?$/) # multiple word line, possible comment
{
my($flag) = $1;
appendArrayFlag($cur_array, $flag, split(' ', $2));
}
else
{
die "Error: unknown build flag at '$line'\n";
}
}
close(FLAGS_FILE);
}
#-------------------------------------------------------------------------------
# flagsArrayToHash
#
# Utility routine to migrate flag from a 2D array to a hash, where
# item[n][0] is the hash entry name, and item[n][1] is the hash entry value.
#-------------------------------------------------------------------------------
sub flagsArrayToHash($$)
{
my($src_array, $dest_hash) = @_;
my($item);
foreach $item (@$src_array)
{
$dest_hash->{$item->[0]} = $item->[1];
}
}
#-----------------------------------------------
# printHash
#
# Utility routine to print a hash
#-----------------------------------------------
sub printHash($)
{
my($hash_ref) = @_;
print "Printing hash:\n";
my($key, $value);
while (($key, $value) = each (%$hash_ref))
{
print " $key $value\n";
}
}
#-----------------------------------------------
# printBuildArray
#
# Utility routine to print a 2D array
#-----------------------------------------------
sub printBuildArray($)
{
my($build_array) = @_;
my($entry);
foreach $entry (@$build_array)
{
print "$entry->[0] = $entry->[1]\n";
}
}
#-------------------------------------------------------------------------------
# SetBuildFlags
#-------------------------------------------------------------------------------
sub SetBuildFlags($)
{
my($build) = @_;
flagsArrayToHash(\@build_flags, $build);
}
#-------------------------------------------------------------------------------
# SetBuildOptions
#-------------------------------------------------------------------------------
sub SetBuildOptions($)
{
my($options) = @_;
flagsArrayToHash(\@options_flags, $options);
}
#-------------------------------------------------------------------------------
# SetFilepathFlags
#-------------------------------------------------------------------------------
sub SetFilepathFlags($)
{
my($filepath) = @_;
flagsArrayToHash(\@filepath_flags, $filepath);
}
#-------------------------------------------------------------------------------
# SetOptionDefines
#-------------------------------------------------------------------------------
sub SetOptionDefines($)
{
my($optiondefines) = @_;
foreach my $entry (@options_flags)
{
if (defined($entry->[2])) {
$optiondefines->{$entry->[0]}{$entry->[2]} = 1;
}
}
}
#-------------------------------------------------------------------------------
# PropagateAllFlags
#-------------------------------------------------------------------------------
sub PropagateAllFlags($)
{
my($build_array) = @_;
# if "all" is set, set all the flags to 1
unless ($build_array->[0][0] eq "all") { die "Error: 'all' must come first in the flags array\n"; }
if ($build_array->[0][1] == 1)
{
my($index);
foreach $index (@$build_array)
{
$index->[1] = 1;
}
}
}
#//--------------------------------------------------------------------------------------------------
#// _getBuildProgressFile
#//--------------------------------------------------------------------------------------------------
sub _getBuildProgressFile()
{
return $progress_file;
}
#//--------------------------------------------------------------------------------------------------
#// setBuildProgressStart
#//
#// This automagically sets $build{"all"} to 0
#//--------------------------------------------------------------------------------------------------
sub setBuildProgressStart($$)
{
my($build_array, $name) = @_;
my($index);
foreach $index (@$build_array)
{
$index->[1] = 0;
if ($index->[0] eq $name) {
last;
}
}
print "Building from module after $name, as specified by build progress\n";
}
#//--------------------------------------------------------------------------------------------------
#// InitBuildProgress
#//--------------------------------------------------------------------------------------------------
sub InitBuildProgress($)
{
my($prog_file) = @_;
if ($prog_file ne "") {
$progress_file = full_path_to($prog_file);
print "Writing build progress to $progress_file\n";
}
}
#//--------------------------------------------------------------------------------------------------
#// WriteBuildProgress
#//--------------------------------------------------------------------------------------------------
sub WriteBuildProgress($)
{
my($module_built) = @_;
my($progress_file) = _getBuildProgressFile();
if ($progress_file ne "")
{
open(PROGRESS_FILE, ">>$progress_file") || die "Failed to open $progress_file\n";
print(PROGRESS_FILE "$module_built\n");
close(PROGRESS_FILE);
}
}
#//--------------------------------------------------------------------------------------------------
#// ClearBuildProgress
#//--------------------------------------------------------------------------------------------------
sub ClearBuildProgress()
{
my($progress_file) = _getBuildProgressFile();
if ($progress_file ne "") {
unlink $progress_file;
}
}
#//--------------------------------------------------------------------------------------------------
#// WipeBuildProgress
#//--------------------------------------------------------------------------------------------------
sub WipeBuildProgress()
{
print "Ignoring build progress\n";
ClearBuildProgress();
$progress_file = "";
}
#//--------------------------------------------------------------------------------------------------
#// ReadBuildProgress
#//--------------------------------------------------------------------------------------------------
sub ReadBuildProgress($)
{
my($build_array) = @_;
my($progress_file) = _getBuildProgressFile();
my($last_module);
if (open(PROGRESS_FILE, "< $progress_file"))
{
print "Getting build progress from $progress_file\n";
while (<PROGRESS_FILE>)
{
my($line) = $_;
chomp($line);
$last_module = $line;
}
close(PROGRESS_FILE);
}
if ($last_module)
{
setBuildProgressStart($build_array, $last_module);
}
}
#-------------------------------------------------------------------------------
# clearOldBuildSettings
#-------------------------------------------------------------------------------
sub clearOldBuildSettings($$$$)
{
my($build, $options, $optiondefines, $filepaths) = @_;
# empty the arrays in case we're being called twice
@build_flags = ();
@options_flags = ();
@filepath_flags = ();
# and empty the hashes
%$build = ();
%$options = ();
%$optiondefines = ();
%$filepaths = ();
}
#-------------------------------------------------------------------------------
# SetupBuildParams
#-------------------------------------------------------------------------------
sub SetupBuildParams($$$$$$)
{
my($build, $options, $optiondefines, $filepaths, $flags_file, $prefs_file) = @_;
# Empty the hashes and arrays, to wipe out any stale data.
# Needed because these structures persist across two build scripts
# called using 'do' from a parent script.
clearOldBuildSettings($build, $options, $optiondefines, $filepaths);
# Read from the flags file, which sets up the various arrays
readFlagsFile($flags_file);
# If 'all' is set in the build array, propagate that to all entries
PropagateAllFlags(\@build_flags);
# read the user pref file, that can change values in the array
ReadMozUserPrefs($prefs_file, \@build_flags, \@options_flags, \@filepath_flags);
# If build progress exists, this clears flags in the array up to a certain point
if ($main::USE_BUILD_PROGRESS) {
ReadBuildProgress(\@build_flags);
} else {
WipeBuildProgress();
}
# printBuildArray(\@build_flags);
# printBuildArray(\@options_flags);
SetBuildFlags($build);
SetBuildOptions($options);
SetOptionDefines($optiondefines);
SetFilepathFlags($filepaths);
# printHash($build);
# printHash($options);
}
1;

View File

@@ -1,786 +0,0 @@
package Moz::BuildUtils;
require 5.004;
require Exporter;
# Package that contains build util functions specific to the Mozilla build
# process.
use strict;
use Exporter;
use Cwd;
use File::Path;
use File::Basename;
use Mac::Events;
use Mac::StandardFile;
use Moz::Moz;
use Moz::BuildFlags;
use Moz::MacCVS;
#use Moz::ProjectXML; #optional; required for static build only
use vars qw(@ISA @EXPORT);
@ISA = qw(Exporter);
@EXPORT = qw(
SetupDefaultBuildOptions
SetupBuildRootDir
StartBuildModule
EndBuildModule
GetBinDirectory
BuildOneProjectWithOutput
BuildOneProject
BuildProject
BuildProjectClean
BuildIDLProject
BuildFolderResourceAliases
AskAndPersistFile
DelayFor
TimeStart
TimeEnd
EmptyTree
SetupBuildLog
SetBuildNumber
SetTimeBomb
UpdateConfigHeader
);
#//--------------------------------------------------------------------------------------------------
#// SetupDefaultBuildOptions
#//--------------------------------------------------------------------------------------------------
sub SetupDefaultBuildOptions($$$)
{
my($debug, $bin_dir, $config_header_file_name) = @_;
# Here we set up defaults for the various build flags.
# If you want to override any of these, it's best to do
# so via the relevant preferences file, which lives in
# System Folder:Preferences:Mozilla build prefs:{build prefs file}.
# For the name of the prefs file, see the .pl script that you
# run to start this build. The prefs files are created when
# you run the build, and contain some documentation.
#-------------------------------------------------------------
# configuration variables that globally affect what is built
#-------------------------------------------------------------
$main::DEBUG = $debug;
$main::PROFILE = 0;
$main::RUNTIME = 0; # turn on to just build runtime support and NSPR projects
$main::GC_LEAK_DETECTOR = 0; # turn on to use GC leak detection
$main::MOZILLA_OFFICIAL = 0; # generate build number
$main::LOG_TO_FILE = 0; # write perl output to a file
#-------------------------------------------------------------
# configuration variables that affect the manner of building,
# but possibly affecting the outcome.
#-------------------------------------------------------------
$main::ALIAS_SYM_FILES = $main::DEBUG;
$main::CLOBBER_LIBS = 1; # turn on to clobber existing libs and .xSYM files before
# building each project
# The following two options will delete all dist files (if you have $main::build{dist} turned on),
# but leave the directory structure intact.
$main::CLOBBER_DIST_ALL = 1; # turn on to clobber all aliases/files inside dist (headers/xsym/libs)
$main::CLOBBER_DIST_LIBS = 0; # turn on to clobber only aliases/files for libraries/sym files in dist
$main::CLOBBER_IDL_PROJECTS = 0; # turn on to clobber all IDL projects.
$main::CLOBBER_PROJECTS = 0; # turn on to remove object code from each project before building it
$main::UNIVERSAL_INTERFACES_VERSION = 0x0320;
#-------------------------------------------------------------
# configuration variables that are preferences for the build,
# style and do not affect what is built.
#-------------------------------------------------------------
$main::CLOSE_PROJECTS_FIRST = 0;
# 1 = close then make (for development),
# 0 = make then close (for tinderbox).
$main::USE_TIMESTAMPED_LOGS = 0;
$main::USE_BUILD_PROGRESS = 1; # track build progress for restartable builds
#-------------------------------------------------------------
# END OF CONFIG SWITCHES
#-------------------------------------------------------------
$main::BIN_DIRECTORY = $bin_dir;
$main::DEFINESOPTIONS_FILE = $config_header_file_name;
}
#//--------------------------------------------------------------------------------------------------
#// SetupBuildRootDir
#//--------------------------------------------------------------------------------------------------
sub SetupBuildRootDir($)
{
my($rel_path_to_script) = @_;
my($cur_dir) = cwd();
$cur_dir =~ s/$rel_path_to_script$//;
chdir($cur_dir) || die "Error: failed to set build root directory to '$cur_dir'.\nYou probably need to put 'mozilla' one level down (in a folder).\n";
$main::MOZ_SRC = cwd();
}
#//--------------------------------------------------------------------------------------------------
#// StartBuildModule
#//--------------------------------------------------------------------------------------------------
sub StartBuildModule($)
{
my($module) = @_;
print("---- Start of $module ----\n");
}
#//--------------------------------------------------------------------------------------------------
#// EndBuildModule
#//--------------------------------------------------------------------------------------------------
sub EndBuildModule($)
{
my($module) = @_;
WriteBuildProgress($module);
print("---- End of $module ----\n");
}
#--------------------------------------------------------------------------------------------------
# GetBinDirectory
#--------------------------------------------------------------------------------------------------
sub GetBinDirectory()
{
if ($main::BIN_DIRECTORY eq "") { die "Dist directory not set\n"; }
return $main::BIN_DIRECTORY;
}
#--------------------------------------------------------------------------------------------------
# AskAndPersistFile stores the information about the user pick inside
# the file $session_storage
#--------------------------------------------------------------------------------------------------
sub AskAndPersistFile($)
{
my ($sessionStorage) = @_;
my $cvsfile;
if (( -e $sessionStorage) &&
open( SESSIONFILE, $sessionStorage ))
{
# Read in the path if available
$cvsfile = <SESSIONFILE>;
chomp $cvsfile;
close SESSIONFILE;
if ( ! -e $cvsfile )
{
print STDERR "$cvsfile has disappeared\n";
undef $cvsfile;
}
}
unless (defined ($cvsfile))
{
# make sure that MacPerl is a front process
ActivateApplication('McPL');
MacPerl::Answer("Could not find your MacCVS session file. Please choose one", "OK");
# prompt user for the file name, and store it
my $macFile = StandardGetFile( 0, "McvD");
if ( $macFile->sfGood() )
{
$cvsfile = $macFile->sfFile();
# save the choice if we can
if ( open (SESSIONFILE, ">" . $sessionStorage))
{
printf SESSIONFILE $cvsfile, "\n";
close SESSIONFILE;
}
else
{
print STDERR "Could not open storage file $sessionStorage for saving $cvsfile\n";
}
}
}
return $cvsfile;
}
#--------------------------------------------------------------------------------------------------
# BuildIDLProject
#
#--------------------------------------------------------------------------------------------------
sub BuildIDLProject($$)
{
my ($project_path, $module_name) = @_;
if ($main::CLOBBER_IDL_PROJECTS)
{
my (@suffix_list) = (".mcp", ".xml");
my ($project_name, $project_dir, $suffix) = fileparse($project_path, @suffix_list);
if ($suffix eq "") { die "Error: Project, $project_path must end in .xml or .mcp\n"; }
my($datafolder_path);
if ($suffix eq ".xml")
{
$datafolder_path = $project_dir . "_" . $project_name . " Data:";
}
else {
$datafolder_path = $project_dir . $project_name . " Data:";
}
print STDERR "Deleting IDL data folder: $datafolder_path\n";
EmptyTree($datafolder_path);
}
BuildOneProject($project_path, "headers", 0, 0, 0);
BuildOneProject($project_path, $module_name.".xpt", 1, 0, 1);
}
#--------------------------------------------------------------------------------------------------
# CreateStaticLibTargets
#
#--------------------------------------------------------------------------------------------------
sub CreateXMLStaticLibTargets($)
{
my($xml_path) = @_;
my (@suffix_list) = (".xml");
my ($project_name, $project_dir, $suffix) = fileparse($xml_path, @suffix_list);
if ($suffix eq "") { die "XML munging: $xml_path must end in .xml\n"; }
#sniff the file to see if we need to fix up broken Pro5-exported XML
print "Parsing $xml_path\n";
my $ide_version = Moz::ProjectXML::SniffProjectXMLIDEVersion($xml_path);
if ($ide_version eq "4.0")
{
my $new_file = $project_dir.$project_name."2.xml";
print "Cleaning up Pro 5 xml to $new_file\n";
Moz::ProjectXML::CleanupPro5XML($xml_path, $new_file);
unlink $xml_path;
rename ($new_file, $xml_path);
}
my $doc = Moz::ProjectXML::ParseXMLDocument($xml_path);
my @target_list = Moz::ProjectXML::GetTargetsList($doc);
my $target;
my %target_hash; # for easy lookups below
foreach $target (@target_list) { $target_hash{$target} = 1; }
foreach $target (@target_list)
{
if ($target =~ /(.+).shlb$/) # if this is a shared lib target
{
my $target_base = $1;
my $static_target = $target_base.".o";
# ensure that this does not exist already
if ($target_hash{$static_target}) {
print "Static target $static_target already exists in project. Not making\n";
next;
}
print "Making static target '$static_target' from target '$target'\n";
Moz::ProjectXML::CloneTarget($doc, $target, $static_target);
Moz::ProjectXML::SetAsStaticLibraryTarget($doc, $static_target, $static_target);
}
}
print "Writing XML file to $xml_path\n";
my $temp_path = $project_dir."_".$project_name.".xml";
Moz::ProjectXML::WriteXMLDocument($doc, $temp_path, $ide_version);
Moz::ProjectXML::DisposeXMLDocument($doc);
if (-e $temp_path)
{
unlink $xml_path;
rename ($temp_path, $xml_path);
}
else
{
die "Error: Failed to add new targets to XML project\n";
}
}
#//--------------------------------------------------------------------------------------------------
#// ProcessProjectXML
#//
#// Helper routine to allow for XML pre-processing. This should read in the XML, process it,
#// and replace the original file with the processed version.
#//--------------------------------------------------------------------------------------------------
sub ProcessProjectXML($)
{
my($xml_path) = @_;
# we need to manually load Moz::ProjectXML, becaues not everyone will have the
# required perl modules in their distro.
my($cur_dir) = cwd();
chdir(dirname($0)); # change to the script dir
eval "require Moz::ProjectXML";
if ($@) { die "Error: could not do Project XML munging because you do not have the correct XML modules installed. Error is:\n################\n $@################"; }
chdir($cur_dir);
CreateXMLStaticLibTargets($xml_path);
}
#//--------------------------------------------------------------------------------------------------
#// Build one project, and make the alias. Parameters are project path, target name, shared library
#// name, make shlb alias (boolean), make xSYM alias (boolean), and is component (boolean).
#//--------------------------------------------------------------------------------------------------
sub BuildOneProjectWithOutput($$$$$$)
{
my ($project_path, $target_name, $output_name, $alias_lib, $alias_xSYM, $component) = @_;
unless ($project_path =~ m/^$main::BUILD_ROOT.+/) { return; }
my (@suffix_list) = (".mcp", ".xml");
my ($project_name, $project_dir, $suffix) = fileparse($project_path, @suffix_list);
if ($suffix eq "") { die "Error: Project, $project_path must end in .xml or .mcp\n"; }
my($dist_dir) = GetBinDirectory();
# Put libraries in "Essential Files" folder, Components in "Components" folder
my($output_dir) = $component ? "Components:" : "Essential Files:";
my($output_path) = $dist_dir.$output_dir;
if ($main::options{static_build})
{
if ($output_name =~ /\.o$/ || $output_name =~ /\.[Ll]ib$/)
{
$alias_xSYM = 0;
$alias_lib = 1;
$output_path = $main::DEBUG ? ":mozilla:dist:static_libs_debug:" : ":mozilla:dist:static_libs:";
}
}
# if the flag is on to export projects to XML, export and munge them
if ($main::EXPORT_PROJECTS && !($project_path =~ /IDL\.mcp$/))
{
my $xml_out_path = $project_path;
$xml_out_path =~ s/\.mcp$/\.xml/;
# only do this if project is newer?
if (! -e $xml_out_path)
{
ExportProjectToXML(full_path_to($project_path), full_path_to($xml_out_path));
ProcessProjectXML($xml_out_path);
}
}
# if the flag is set to use XML projects, default to XML if the file
# is present.
if ($main::USE_XML_PROJECTS && !($project_path =~ /IDL\.mcp$/))
{
my $xml_project_path = $project_dir.$project_name.".xml";
if (-e $xml_project_path)
{
$project_path = $xml_project_path;
$suffix = ".xml";
}
}
if ($suffix eq ".xml")
{
my($xml_path) = $project_path;
# Prepend an "_" onto the name of the generated project file so it doesn't conflict
$project_path = $project_dir . "_" . $project_name . ".mcp";
my($project_modtime) = (-e $project_path ? GetFileModDate($project_path) : 0);
my($xml_modtime) = (-e $xml_path ? GetFileModDate($xml_path) : 0);
if ($xml_modtime > $project_modtime)
{
print("Importing $project_path from $project_name.xml.\n");
unlink($project_path);
# Might want to delete the "xxx.mcp Data" dir ???
ImportXMLProject(full_path_to($xml_path), full_path_to($project_path));
}
}
if ($main::CLOBBER_LIBS)
{
unlink "$project_dir$output_name"; # it's OK if these fail
unlink "$project_dir$output_name.xSYM";
}
DoBuildProject($project_path, $target_name, $main::CLOBBER_PROJECTS);
$alias_lib ? MakeAlias("$project_dir$output_name", "$output_path") : 0;
$alias_xSYM ? MakeAlias("$project_dir$output_name.xSYM", "$output_path") : 0;
}
#//--------------------------------------------------------------------------------------------------
#// For compatiblity with existing scripts, BuildOneProject now just calls
#// BuildOneProjectWithOutput, with the output name and target name identical.
#// Note that this routine assumes that the target name and the shared libary name
#// are the same.
#//--------------------------------------------------------------------------------------------------
sub BuildOneProject($$$$$)
{
my ($project_path, $target_name, $alias_lib, $alias_xSYM, $component) = @_;
BuildOneProjectWithOutput($project_path, $target_name, $target_name,
$alias_lib, $alias_xSYM, $component);
}
#//--------------------------------------------------------------------------------------------------
#// For compatiblity with existing scripts, BuildProject now just calls
#// BuildOneProjectWithOutput, with the output name and target name identical.
#// Note that this routine assumes that the target name and the shared libary name
#// are the same. No aliases of the output are made.
#//--------------------------------------------------------------------------------------------------
sub BuildProject($$)
{
my ($project_path, $target_name) = @_;
BuildOneProjectWithOutput($project_path, $target_name, $target_name, 0, 0, 0);
}
#//--------------------------------------------------------------------------------------------------
#// Identical to BuildProject but clobbers the project before building it.
#//--------------------------------------------------------------------------------------------------
sub BuildProjectClean($$)
{
my ($project_path, $target_name) = @_;
my ($save_clobber_flag) = $main::CLOBBER_PROJECTS;
$main::CLOBBER_PROJECTS = 1;
BuildOneProjectWithOutput($project_path, $target_name, $target_name, 0, 0, 0);
$main::CLOBBER_PROJECTS = $save_clobber_flag;
}
#//--------------------------------------------------------------------------------------------------
#// Make resource aliases for one directory
#//--------------------------------------------------------------------------------------------------
sub BuildFolderResourceAliases($$)
{
my($src_dir, $dest_dir) = @_;
# get a list of all the resource files
opendir(SRCDIR, $src_dir) || die("can't open $src_dir");
my(@resource_files) = readdir(SRCDIR);
closedir(SRCDIR);
# make aliases for each one into the dest directory
print("Placing aliases to all files from $src_dir in $dest_dir\n");
for ( @resource_files )
{
next if $_ eq "CVS";
#print(" Doing $_\n");
if (-l $src_dir.$_)
{
print(" $_ is an alias\n");
next;
}
my($file_name) = $src_dir . $_;
MakeAlias($file_name, $dest_dir);
}
}
#//--------------------------------------------------------------------------------------------------
#// DelayFor
#//
#// Delay for the given number of seconds, allowing the script to be cancelled
#//--------------------------------------------------------------------------------------------------
sub DelayFor($)
{
my($delay_secs) = @_;
STDOUT->autoflush(1);
my($end_time) = time() + $delay_secs;
my($last_time) = 0;
my($cur_time) = time();
while ($cur_time < $end_time)
{
$cur_time = time();
if ($cur_time > $last_time)
{
print ".";
$last_time = $cur_time;
}
WaitNextEvent();
}
print "\n";
STDOUT->autoflush(0);
}
#//--------------------------------------------------------------------------------------------------
#// TimeStart
#//--------------------------------------------------------------------------------------------------
sub TimeStart()
{
return time();
}
#//--------------------------------------------------------------------------------------------------
#// TimeEnd
#//--------------------------------------------------------------------------------------------------
sub TimeEnd($$)
{
use integer;
my($start_time, $operation_name) = @_;
my($end_time) = time();
my($tot_sec) = $end_time - $start_time;
my($seconds) = $tot_sec;
my($hours) = $seconds / (60 * 60);
$seconds -= $hours * (60 * 60);
my($minutes) = $seconds / 60;
$seconds -= $minutes * 60;
print "$operation_name took $hours hours $minutes minutes and $seconds seconds\n";
}
#//--------------------------------------------------------------------------------------------------
#// Remove all files from a tree, leaving directories intact (except "CVS").
#//--------------------------------------------------------------------------------------------------
sub EmptyTree($)
{
my ($root) = @_;
#print "EmptyTree($root)\n";
opendir(DIR, $root);
my $sub;
foreach $sub (readdir(DIR))
{
my $fullpathname = $root.$sub; # -f, -d only work on full paths
# Don't call empty tree for the alias of a directory.
# -d returns true for the alias of a directory, false for a broken alias)
if (-d $fullpathname)
{
if (-l $fullpathname) # delete aliases
{
unlink $fullpathname;
next;
}
EmptyTree($fullpathname.":");
if ($sub eq "CVS")
{
#print "rmdir $fullpathname\n";
rmdir $fullpathname;
}
}
else
{
unless (unlink $fullpathname) { die "Failed to delete $fullpathname\n"; }
}
}
closedir(DIR);
}
#//--------------------------------------------------------------------------------------------------
#// Recurse through a directory hierarchy, looking for MANIFEST files.
#// Currently unused.
#//--------------------------------------------------------------------------------------------------
sub ScanForManifestFiles($$$$)
{
my($dir, $theme_root, $theme_name, $dist_dir) = @_;
opendir(DIR, $dir) or die "Cannot open dir $dir\n";
my @files = readdir(DIR);
closedir DIR;
my $file;
foreach $file (@files)
{
my $filepath = $dir.":".$file;
if (-d $filepath)
{
# print "Looking for MANIFEST files in $filepath\n";
ScanForManifestFiles($filepath, $theme_root, $theme_name, $dist_dir);
}
elsif ($file eq "MANIFEST")
{
# print "Doing manifest file $filepath\n";
# Get the dest path from the first line of the file
open(MANIFEST, $filepath) || die "Could not open file $file";
# Read in the path if available
my($dest_line) = <MANIFEST>;
chomp $dest_line;
close MANIFEST;
$dest_line =~ s|^#!dest[\t ]+|| || die "No destination line found in $filepath\n";
my($dest_path) = $dist_dir."chrome:skins:$theme_name:$dest_line";
# print " Destination is $dest_path\n";
InstallResources($filepath, "$dest_path", 0);
}
}
}
#-----------------------------------------------
# SetupBuildLog
#-----------------------------------------------
sub SetupBuildLog($$)
{
my($logfile_path, $timestamped_log) = @_;
my($logdir) = "";
my($logfile) = $logfile_path;
if ($logfile_path =~ /(.+?:)([^:]+)$/) # ? for non-greedy match
{
$logdir = $1;
$logfile = $2;
mkpath($logdir);
}
if ($timestamped_log)
{
#Use time-stamped names so that you don't clobber your previous log file!
my $now = localtime();
while ($now =~ s@:@.@) {} # replace all colons by periods
OpenErrorLog("${logdir}${now}");
}
else
{
OpenErrorLog("${logdir}${logfile}");
}
}
#-----------------------------------------------
# SetBuildNumber
#-----------------------------------------------
sub SetBuildNumber($$)
{
my($build_num_file, $files_to_touch) = @_;
# Make sure we add the config dir to search, to pick up mozBDate.pm
# Need to do this dynamically, because this module can be used before
# mozilla/config has been checked out.
my ($inc_path) = $0; # $0 is the path to the parent script
$inc_path =~ s/:build:mac:build_scripts:.+$/:config/;
push(@INC, $inc_path);
require mozBDate;
mozBDate::UpdateBuildNumber($build_num_file, $main::MOZILLA_OFFICIAL);
my($file);
foreach $file (@$files_to_touch)
{
print "Writing build number to $file from ${file}.in\n";
mozBDate::SubstituteBuildNumber($file, $build_num_file, "${file}.in");
}
}
#-----------------------------------------------
# SetTimeBomb
#-----------------------------------------------
sub SetTimeBomb($$)
{
my ($warn_days, $bomb_days) = @_;
system("perl :mozilla:config:mac-set-timebomb.pl $warn_days $bomb_days");
}
#//--------------------------------------------------------------------------------------------------
#// Regenerate a configuration header file if necessary
#//--------------------------------------------------------------------------------------------------
sub UpdateConfigHeader($)
{
my($config_path) = @_;
my($config, $oldconfig) = ("", "");
my($define, $definevalue, $defines);
my($k, $l,);
foreach $k (keys(%main::options))
{
if ($main::options{$k})
{
foreach $l (keys(%{$main::optiondefines{$k}}))
{
$my::defines{$l} = $main::optiondefines{$k}{$l};
print "Setting up my::defines{$l}\n";
}
}
}
my $config_headerfile = current_directory().$config_path;
if (-e $config_headerfile)
{
open(CONFIG_HEADER, "< $config_headerfile") || die "$config_headerfile: $!\n";
my($line);
while ($line = <CONFIG_HEADER>)
{
if ($line =~ m/#define\s+([^\s]*)\s+([^\s]*)\s*\n/)
{
$define = $1;
$definevalue = $2;
#canonicalize so that whitespace changes are not significant
my $canon_value = "#define " . $define . " " . $definevalue . "\n";
$oldconfig .= $canon_value;
if (exists ($my::defines{$define}) and ($my::defines{$define} == $definevalue))
{
delete $my::defines{$define};
$config .= $canon_value;
}
}
}
close(CONFIG_HEADER);
}
if (%my::defines)
{
foreach $k (keys(%my::defines))
{
$config .= "#define " . $k . " " . $my::defines{$k} . "\n";
}
}
my $file_name = basename($config_headerfile);
if (($config ne $oldconfig) || (!-e $config_headerfile))
{
printf("Writing new configuration header $file_name\n");
open(CONFIG_HEADER, "> $config_headerfile") || die "$config_headerfile: $!\n";
print(CONFIG_HEADER "/* This file is auto-generated based on build options. Do not edit. */\n");
print CONFIG_HEADER ($config);
close(CONFIG_HEADER);
MacPerl::SetFileInfo("CWIE", "TEXT", $config_headerfile);
}
else
{
printf("Configuration header $file_name is up-to-date\n");
}
}
1;

View File

@@ -1,660 +0,0 @@
#!perl
package Moz::CodeWarriorLib;
=pod
=head1 NAME
CodeWarriorLib - supply interface to CodeWarrior
=head1 SYNOPSIS
#!perl
use CodeWarriorLib;
CodeWarriorLib::activate();
$had_errors = CodeWarriorLib::build_project(
$project_path, $target_name, $recent_errors_file, $clean_build
);
=head1 DESCRIPTION
Replaces the AppleScript library I<CodeWarriorLib>.
=over 4
=cut
use strict;
use Cwd;
use File::Basename;
use Mac::Types;
use Mac::Events;
use Mac::AppleEvents;
use Mac::AppleEvents::Simple;
use Mac::Processes;
use Mac::MoreFiles;
use Mac::StandardFile;
use vars qw($VERSION);
$VERSION = '1.02';
my($app) = 'CWIE';
my($scriptDir) = cwd(); # could use $0 for this
my($ide_loc_file) = "";
# 0 == don't switch CWIE to front app in do_event(), 1 == do switch
# note: activate() still switches when called
$Mac::AppleEvents::Simple::SWITCH = 0;
# $Mac::AppleEvents::Simple::WARN = 1;
# supply your own path to the source here
#_test('PowerPudgeIV:mozilla:mozilla:');
# If you want to understand the gobbldeygook that's used to build Apple Events,
# you should start by reading the AEGizmos documentation.
=pod
=item _get_project($full_path)
A private routine returning a reference to the open project with the given name,
or else the empty string (when that project is not open)
full_path is a string identifying the project to be built and is of the form,
e.g., "HD:ProjectFolder:MyProject.mcp". It must be supplied.
=cut
sub _get_project ($) {
my(
$full_path, $candidate_projects
) = @_;
$candidate_projects = _doc_named(basename($full_path, '*'));
if ($candidate_projects) {
my($cps) = _get_dobj($candidate_projects);
my($num) = AECountItems($cps);
if ($num) { # is a list
foreach (1 .. AECountItems($cps)) {
my($cp) = AEGetNthDesc($cps, $_);
if (lc $full_path eq lc _full_path($cp)) {
return($cp);
}
}
} else { # is only one, not a list
if (lc $full_path eq lc _full_path($cps)) {
return($cps);
}
}
}
return;
}
=pod
=item build_project
Build a selected target of a project, saving any errors to a file, if supplied.
full_path is a string identifying the project to be built and is of the form,
e.g., "HD:ProjectFolder:MyProject.mcp". It must be supplied.
If target_name is the empty string, the current target of the selected project
will be built, else, target_name should be a string matching a target name in
the selected project.
If error_path is the empty string, errors will not be saved to a file,
else, error_path should be the full path of a file to save error messages into.
=cut
$CodeWarriorLib::CLOSE_PROJECTS_FIRST = 0; # If true we close then make. If false, make then close.
my $last_project_built = "";
my $last_project_was_closed = 0;
sub build_project ($;$$$) {
my(
$full_path, $target_name, $error_path,
$remove_object, $p, $project_was_closed, $had_errors
) = @_;
_close_errors_window();
if ($CodeWarriorLib::CLOSE_PROJECTS_FIRST && ($last_project_built ne $full_path))
{
# If we're in "close first" mode, we don't close if the current project
# is the same as the previous one.
if ($last_project_was_closed) {
$p = _get_project($last_project_built);
_close($p);
}
$last_project_built = $full_path;
$last_project_was_closed = 0; # now refers to the new project
}
$project_was_closed = 0;
while (1) {
$p = _get_project($full_path);
if (!$p) {
if ($project_was_closed) {
print "### Error - request for project document failed after opening\n";
die "### possibly CW Pro 4 bug: be sure to close your Find window\n";
}
$project_was_closed = 1;
$last_project_was_closed = 1;
_open_file($full_path);
} else {
last;
}
}
$had_errors = 0;
if ($target_name eq '') {
if ($remove_object) {_remove_object($p)}
_build($p);
} else {
if ($remove_object) {_remove_object($p, $target_name)}
_build($p, $target_name);
}
if ($error_path ne '') {
_save_errors_window($error_path);
}
$had_errors = _close_errors_window();
if (!$CodeWarriorLib::CLOSE_PROJECTS_FIRST)
{
if ($project_was_closed) {
$p = _get_project($full_path);
_close($p);
}
}
return($had_errors);
}
=pod
=item appIsRunning()
=cut
sub _appIsRunning($)
{
my ($appSignature) = @_;
my ($psi);
my ($found) = 0;
my ($appPSN);
foreach $psi (values(%Process))
{
if ($psi->processSignature() eq $appSignature)
{
$appPSN = $psi->processNumber();
$found = 1;
last;
}
}
return $found;
}
=pod
=item appIsFrontmost()
=cut
sub _appIsFrontmost($)
{
my ($appSignature) = @_;
my ($psi);
my ($found) = 0;
my ($appPSN);
foreach $psi (values(%Process))
{
if ($psi->processSignature() eq $appSignature)
{
$appPSN = $psi->processNumber();
$found = 1;
last;
}
}
return (GetFrontProcess() == $appPSN);
}
=pod
=item activate()
Launches CodeWarrior and brings it to the front.
Once found, path will be saved in $idepath_file for future reference.
Edit or delete this file to change the location of the IDE. If app is
moved, C<activate()> will prompt for a new location.
First looks for an open CodeWarrior app. Second, tries to open previously
saved location in ':idepath.txt'. Third, tries to find it and allow user
to choose it with Navigation Services (if present). Fourth, uses good old
GUSI routines built-in to MacPerl for a Choose Directory dialog box.
=cut
sub activate ($) {
$ide_loc_file = $_[0]; # save in global
my($filepath, $appath, $psi) = ($ide_loc_file);
foreach $psi (values(%Process)) {
if ($psi->processSignature() eq $app) {
$appath = $psi->processAppSpec();
_save_appath($filepath, $appath);
last;
}
}
if (!$appath || !-x $appath) {
$appath = _read_appath($filepath);
}
if (!$appath || ! -x $appath)
{
# make sure that MacPerl is a front process
#ActivateApplication('McPL');
MacPerl::Answer("Please locate the CodeWarrior application.", "OK");
# prompt user for the file name, and store it
my $macFile = StandardGetFile( 0, "APPL");
if ( $macFile->sfGood() )
{
$appath = $macFile->sfFile();
}
else
{
die "Operation canceled\n";
}
# if (eval {require Mac::Navigation}) {
# my($options, $nav);
# Mac::Navigation->import();
# $options = NavGetDefaultDialogOptions();
# $options->message('Where is CodeWarrior IDE?');
# $options->windowTitle('Find CodeWarrior IDE');
# $nav = NavChooseObject($Application{$app}, $options);
# die "CodeWarrior IDE not found.\n" if (!$nav || !$nav->file(1));
# $appath = $nav->file(1);
# } else {
# local(*D);
# my $cwd = `pwd`;
# $appath = _get_folder(
# 'Where is the CW IDE folder?',
# dirname($Application{$app})
# );
# die "CodeWarrior IDE not found.\n" if !$appath;
# opendir(D, $appath) or die $!;
# chdir($appath);
# foreach my $file (sort readdir (D)) {
# my(@app) = MacPerl::GetFileInfo($file);
# if ($app[0] && $app[1] &&
# $app[1] eq 'APPL' && $app[0] eq $app
# ) {
# $appath .= $file;
# last;
# }
# }
# chomp($cwd);
# chdir($cwd);
# }
_save_appath($filepath, $appath);
}
my($lp) = LaunchParam->new(
launchAppSpec => $appath,
launchControlFlags => launchContinue() + launchNoFileFlags()
);
unless (LaunchApplication($lp)) {
unlink($filepath);
die $^E;
}
# wait for CodeWarrior to show up in the list of processes
while (!_appIsRunning('CWIE'))
{
WaitNextEvent();
}
# wait for CodeWarrior to come to the front
while (!_appIsFrontmost('CWIE'))
{
WaitNextEvent();
}
}
=pod
=item getCodeWarriorPath()
Returns a file path relative to the CodeWarrior folder
=cut
sub getCodeWarriorPath($)
{
my($subfolder)=@_;
my($app_path) = _read_appath($ide_loc_file);
if ($app_path eq "") { die "Error: Failed to get CodeWarrior IDE path\n"; }
my($codewarrior_root) = $app_path;
$codewarrior_root =~ s/[^:]*$//;
return ($codewarrior_root . $subfolder);
}
=pod
=item getCodeWarriorIDEName()
Returns the name of the CodeWarrior application
=cut
sub getCodeWarriorIDEName()
{
my($subfolder)=@_;
my($app_path) = _read_appath($ide_loc_file);
if ($app_path eq "") { die "Error: Failed to get CodeWarrior IDE path\n"; }
my(@codewarrior_path) = split(/:/, $app_path);
return pop(@codewarrior_path);
}
=pod
=item quit()
Quits CodeWarrior.
=cut
sub quit() {
$last_project_built = "";
$last_project_was_closed = 0;
my($evt) = do_event(qw/aevt quit/, $app);
}
sub _build ($;$) {
my($evt);
if ($_[1]) {
my($prm) =
q"'----':obj {form:name, want:type(TRGT), seld:TEXT(@), from:" .
AEPrint($_[0]) . '}';
$evt = do_event(qw/CWIE MAKE/, $app, $prm, $_[1]);
} else {
my($prm) = q"'----':" . AEPrint($_[0]);
$evt = do_event(qw/CWIE MAKE/, $app, $prm);
}
}
sub _remove_object ($;$) {
my($evt);
if ($_[1]) {
my($prm) =
q"'----':obj {form:name, want:type(TRGT), seld:TEXT(@), from:" .
AEPrint($_[0]) . '}';
$evt = do_event(qw/CWIE RMOB/, $app, $prm, $_[1]);
} else {
my($prm) = q"'----':" . AEPrint($_[0]);
$evt = do_event(qw/CWIE RMOB/, $app, $prm);
}
}
sub _open_file ($) {
my($prm) =
q"'----':obj {form:name, want:type(alis), " .
q"seld:TEXT(@), from:'null'()}";
do_event(qw/aevt odoc/, $app, $prm, $_[0]);
}
sub import_project ($$) {
my($xml_file, $project_path) = @_;
my($prm) = "kocl:type(PRJD), rtyp:TEXT(@), data:TEXT(@), &subj:'null'()";
my($evt) = do_event(qw/core crel/, $app, $prm, $project_path, $xml_file);
my($result) = _get_event_result($evt);
if ($result eq "") {
_close(_get_project($project_path));
}
return $result;
}
sub export_project ($$) {
my($project_path, $xml_out_path) = @_;
my($p, $project_was_closed);
$project_was_closed = 0;
while (1) {
$p = _get_project($project_path);
if (!$p) {
if ($project_was_closed) {
print "### Error - request for project document failed after opening\n";
die "### possibly CW bug: be sure to close your Find window\n";
}
$project_was_closed = 1;
_open_file($project_path);
} else {
last;
}
}
# avoid problems with the Project Messages window
_close_named_window("Project Messages");
my($prm) =
q"'----':obj {form:indx, want:type(PRJD), " .
q"seld:1, from:'null'()}, kfil:TEXT(@)";
my($evt) = do_event(qw/CWIE EXPT/, $app, $prm, $xml_out_path);
if ($project_was_closed) {
$p = _get_project($project_path);
_close($p);
}
return _get_event_result($evt);
}
sub _doc_named ($) {
my($prm) =
q"'----':obj {form:test, want:type(docu), from:'null'(), " .
q"seld:cmpd{relo:'= ', 'obj1':obj {form:prop, want:type" .
q"(prop), seld:type(pnam), from:'exmn'()}, 'obj2':TEXT(@)}}";
my($evt) = do_event(qw/core getd/, $app, $prm, $_[0]);
return($evt->{REPLY} eq 'aevt\ansr{}' ? undef : $evt);
}
sub _full_path ($) {
my($obj) = $_[0];
my($prm) =
q"'----':obj {form:prop, want:type(prop), seld:type(FILE), " .
q"from:" . AEPrint($_[0]) . q"}, rtyp:type(TEXT)";
my($evt) = do_event(qw/core getd/, $app, $prm);
return MacPerl::MakePath(
MacUnpack('fss ', (
AEGetParamDesc($evt->{REP}, keyDirectObject()))->data()->get()
)
);
}
sub _save_errors_window ($) {
my($prm) =
q"'----':obj {form:name, want:type(alis), seld:TEXT(@), from:'null'()}";
do_event(qw/MMPR SvMs/, $app, $prm, $_[0]);
}
sub _close_errors_window () {
return _close_named_window('Errors & Warnings');
}
sub _close_named_window ($) {
my($window_name) = @_;
my($prm) =
q"'----':obj {form:name, want:type(cwin), " .
q"seld:TEXT(@), from:'null'()}";
my($evt) = do_event(qw/core clos/, $app, $prm, $window_name);
return($evt->{REPLY} eq 'aevt\ansr{}' ? 1 : 0);
}
sub _close () {
my($prm) = q"'----':" . AEPrint($_[0]);
do_event(qw/core clos/, $app, $prm);
}
sub _get_dobj ($) {
return(AEGetParamDesc($_[0]->{REP}, keyDirectObject()));
}
sub _get_folder ($$) {
require 'GUSI.ph';
my($prompt, $default) = @_;
MacPerl::Choose(
GUSI::AF_FILE(), 0, $prompt, '',
GUSI::CHOOSE_DIR() + ($default ? &GUSI::CHOOSE_DEFAULT : 0),
$default
);
}
sub _get_event_result ($)
{
my($evt) = @_;
my($result) = $evt->{ERROR};
if ( $result eq "" && $evt->{ERRNO} != 0 )
{
$result = "unknown error (".$evt->{ERRNO}.")";
}
return $result;
}
sub _save_appath ($$) {
my($cwd) = cwd(); # remember the current working dir
chdir($scriptDir); # change dir to the script dir
local(*F);
open(F, '>' . $_[0]) or die $!;
print F $_[1];
close(F);
chdir($cwd); # restore the cwd
}
sub _read_appath ($) {
my($filepath) = @_;
my($cwd) = cwd(); # remember the current working dir
chdir($scriptDir); # change dir to the script dir
if (! -e $filepath) {
return "";
}
local(*F);
open(F, $filepath);
my($appath) = <F>;
close(F);
chdir($cwd); # restore the cwd
return($appath);
}
sub _test ($) {
activate($ide_loc_file);
my($path) = $_[0];
build_project(
"${path}modules:xml:macbuild:XML.mcp", '',
"${path}build:mac:Mozilla.BuildLog.part"
);
}
1;
=pod
=back
=head1 HISTORY
=over 4
=item v1.02, September 23, 1998
Made fixes in finding and saving location of CodeWarrior IDE.
=item v1.01, June 1, 1998
Made fixes to C<chdir()> in C<activate()>, made C<activate()> more robust
in finding CodeWarrior IDE, added global variable to NOT switch to IDE
for each sent event, a few other fixes.
=item v1.00, May 30, 1998
First shot
=back
=head1 AUTHORS
Chris Nandor F<E<lt>pudge@pobox.comE<gt>>, and the author of the
original I<CodeWarriorLib>, Scott Collins F<E<lt>scc@netscape.comE<gt>>.
=head1 SEE ALSO
BuildProject L<Moz>.
=head1 COPYRIGHT
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 Communicator client code, released
March 31, 1998.
The Initial Developer of the Original Code is Netscape
Communications Corporation. Portions created by Netscape are
Copyright (C) 1998-1999 Netscape Communications Corporation. All
Rights Reserved.
Contributor(s):
=cut

View File

@@ -1,576 +0,0 @@
#!perl -w
package Moz::Jar;
#
# Module for creating jar files, either using a jar manifest, or
# simply jarring up folders on disk.
#
require 5.004;
require Exporter;
use strict;
use Archive::Zip;
use File::Path;
use Mac::Files;
use Moz::Moz;
use vars qw( @ISA @EXPORT );
@ISA = qw(Exporter);
@EXPORT = qw(
CreateJarFileFromDirectory
CreateJarFromManifest
WriteOutJarFiles
SanityCheckJarOptions
);
#-------------------------------------------------------------------------------
# Add the contents of a directory to the zip file
#
#-------------------------------------------------------------------------------
sub _addDirToJar($$$$)
{
my($dir, $jar_root, $zip, $compress) = @_;
opendir(DIR, $dir) or die "Error: Cannot open dir $dir\n";
my @files = readdir(DIR);
closedir DIR;
my $unix_jar_root = $jar_root;
$unix_jar_root =~ s|:|/|g; # colon to slash conversion
my $file;
foreach $file (@files)
{
my $filepath = $dir.":".$file;
if (-d $filepath)
{
print "Adding files to jar from $filepath\n";
_addDirToJar($filepath, $jar_root, $zip, $compress);
}
else
{
my $member = Archive::Zip::Member->newFromFile($filepath);
die "Error: Failed to create zip file member $filepath\n" unless $member;
my $unixName = $filepath;
$unixName =~ s|:|/|g; # colon to slash conversion
$unixName =~ s|^$unix_jar_root||; # relativise
$member->fileName($unixName);
# print "Adding $file as $unixName\n";
if ($compress) {
$member->desiredCompressionMethod(Archive::Zip::COMPRESSION_DEFLATED);
} else {
$member->desiredCompressionMethod(Archive::Zip::COMPRESSION_STORED);
}
$zip->addMember($member);
}
}
}
#-------------------------------------------------------------------------------
# Add the contents of a directory to the zip file
#
#-------------------------------------------------------------------------------
sub CreateJarFileFromDirectory($$$)
{
my($srcdir, $jarpath, $compress) = @_;
my $zip = Archive::Zip->new();
_addDirToJar($srcdir, $srcdir, $zip, $compress);
print "Saving zip file...\n";
my $status = $zip->writeToFileNamed($jarpath);
if ($status == 0) {
print "Zipping completed successfully\n";
} else {
print "Error saving zip file\n";
}
# set the file type/creator to something reasonable
MacPerl::SetFileInfo("ZIP ", "ZIP ", $jarpath);
}
#-------------------------------------------------------------------------------
# printZipContents
#
#-------------------------------------------------------------------------------
sub printZipContents($)
{
my($zip) = @_;
my(@members) = $zip->memberNames();
print "Zip contains:\n";
my($member);
foreach $member (@members)
{
print " $member\n";
}
}
#-------------------------------------------------------------------------------
# safeSaveJarFile
#
# Archive::Zip has a problem where you cannot save a zip file on top of
# an existing zip file that it has open, because it holds references
# into that zip. So we have to save to a temp file, then do a swap.
#
# Note that the zip will become invalid after this operation.
# If you want to do further operations on it, you'll have to reread it.
#-------------------------------------------------------------------------------
sub safeSaveJarFile($$)
{
my($zip, $full_dest_path) = @_;
my($temp_file_name) = $full_dest_path."_temp";
($zip->writeToFileNamed($temp_file_name) == Archive::Zip::AZ_OK) || die "Error: died writing jar to temp file $temp_file_name\n";
unlink $full_dest_path;
(rename $temp_file_name, $full_dest_path) || die "Error: Failed to rename $temp_file_name\n";
MacPerl::SetFileInfo("ZIP ", "ZIP ", $full_dest_path);
}
#-------------------------------------------------------------------------------
# addToJarFile
#
# Add a file to a jar file
#
# Parameters:
# 1. Jar ID. Unix path of jar file inside chrome.
# 2. Abs path to jar.mn file (i.e. source) (mac breaks)
# 3. File source, relative to jar.mn path (mac breaks)
# 4. Abs path to the resulting .jar file (mac breaks)
# 5. Relative file path within the jar (unix breaks)
# 6. Reference to hash of jar files
#
#-------------------------------------------------------------------------------
sub addToJarFile($$$$$$$)
{
my($jar_id, $jar_man_dir, $file_src, $jar_path, $file_jar_path, $override, $jars) = @_;
# print "addToJarFile with:\n $jar_man_dir\n $file_src\n $jar_path\n $file_jar_path\n";
unless ($jar_path =~ m/(.+:)([^:]+)$/) { die "Error: Bad jar path $jar_path\n"; }
my($target_dir) = $1;
my($jar_name) = $2;
$target_dir =~ s/[^:]+$//;
# print "¥ $target_dir $jar_name\n";
# find the source file
my($src) = $jar_man_dir.":".$file_src;
if ((!-e $src) && ($file_src =~ m/.+:([^:]+)$/)) # src does not exist. Fall back to looking for src in jar.mn dir
{
$file_src = $1;
$src = $jar_man_dir.":".$file_src;
if (!-e $src) {
die "Error: Can't find chrome file $src\n";
}
}
if ($main::options{chrome_jars})
{
my($zip) = $jars->{$jar_id};
unless ($zip) { die "Error: Can't find Zip entry for $jar_id\n"; }
# print "Adding $file_src to jar file $jar_path at $file_jar_path\n";
my($member) = Archive::Zip::Member->newFromFile($src);
unless ($member) { die "Error: Failed to create zip file member $src\n"; }
$member->fileName($file_jar_path);
my($compress) = 1;
if ($compress) {
$member->desiredCompressionMethod(Archive::Zip::COMPRESSION_DEFLATED);
$member->desiredCompressionLevel(Archive::Zip::COMPRESSION_LEVEL_DEFAULT); # defaults to 6
} else {
$member->desiredCompressionMethod(Archive::Zip::COMPRESSION_STORED);
}
my($old_member) = $zip->memberNamed($file_jar_path);
if ($override)
{
if ($old_member)
{
# print "Overriding $file_jar_path in jar file $jar_id\n";
# need to compare mod dates or use the + here
$zip->removeMember($old_member);
}
$zip->addMember($member);
}
else
{
if ($old_member)
{
#compare dates here
my($member_moddate) = $old_member->lastModTime();
my($file_moddate) = GetFileModDate($src);
if ($file_moddate > $member_moddate)
{
print "Updating older file $file_jar_path in $jar_id\n";
$zip->removeMember($old_member);
$zip->addMember($member);
}
else
{
print "File $file_jar_path in $jar_id is more recent. Not updating.\n";
}
}
else
{
$zip->addMember($member);
}
}
}
if ($main::options{chrome_files}) # we install raw files too
{
my($rel_path) = $file_jar_path;
$rel_path =~ s|/|:|g; # slash to colons
my($dir_name) = $jar_name;
$dir_name =~ s/\.jar$//;
my($dst) = $target_dir.$dir_name.":".$rel_path;
# print "Aliassing $src\n to\n$dst\n";
if ($override)
{
unlink $dst;
MakeAlias($src, $dst); # don't check errors, otherwise we fail on replacement
}
else
{
if (-e $dst)
{
#compare dates here
my($dst_moddate) = GetFileModDate($dst);
my($file_moddate) = GetFileModDate($src);
if ($file_moddate > $dst_moddate)
{
print "Updating older file $rel_path in $dir_name\n";
unlink $dst;
MakeAlias($src, $dst);
}
else
{
print "File $file_jar_path in $jar_id is more recent. Not updating.\n";
}
}
else
{
MakeAlias($src, $dst);
}
}
}
}
#-------------------------------------------------------------------------------
# setupJarFile
#
# setup a zip for writing
#-------------------------------------------------------------------------------
sub setupJarFile($$$)
{
my($jar_id, $dest_path, $jar_hash) = @_;
# print "Creating jar file $jar_id at $jar_path\n";
my($jar_file) = $jar_id;
$jar_file =~ s|/|:|g; # slash to colons
my($full_jar_path) = full_path_to($dest_path.":".$jar_file);
if ($main::options{chrome_jars})
{
my($zip) = $jar_hash->{$jar_id};
if (!$zip) # if we haven't made it already, do so
{
my($zip) = Archive::Zip->new();
$jar_hash->{$jar_id} = $zip;
# does the jar file exist already? If so, read it in
if (-e $full_jar_path)
{
print "Reading in jar file $jar_id\n";
if ($zip->read($full_jar_path) != Archive::Zip::AZ_OK) { die "Error: Failed to re-read $full_jar_path\n"; }
# printZipContents($zip);
}
}
}
else
{
# installing files.
# nothing to do. MakeAlias creates dirs as needed.
# add this jar to the list
$jar_hash->{$jar_id} = 1;
}
}
#-------------------------------------------------------------------------------
# closeJarFile
#
# We're done with this jar file _for this jar.mn_. We may add more entries
# to it later, so keep it open in the hash.
#-------------------------------------------------------------------------------
sub closeJarFile($$)
{
my($jar_path, $jar_hash) = @_;
# print "Closing jar file $jar_path\n";
if ($main::options{chrome_jars})
{
}
else
{
# installing files.
# nothing to do
}
}
#-------------------------------------------------------------------------------
# WriteOutJarFiles
#
# Now we dump out the jars
#-------------------------------------------------------------------------------
sub WriteOutJarFiles($$)
{
my($chrome_dir, $jars) = @_;
unless ($main::options{chrome_jars}) { return; }
my($full_chrome_path) = full_path_to($chrome_dir);
my($key);
foreach $key (keys %$jars)
{
my($zip) = $jars->{$key};
my($rel_path) = $key;
$rel_path =~ s/\//:/g;
my($output_path) = $full_chrome_path.":".$rel_path;
print "Writing zip file $key to $output_path\n";
# ensure the target dirs exist
my($path) = $output_path;
$path =~ s/[^:]+$//;
mkpath($path);
# unlink $output_path; # remove any existing jar
safeSaveJarFile($zip, $output_path);
# $zip is invalid after this operation, so nuke it here
$jars->{$key} = 0;
}
}
#-------------------------------------------------------------------------------
# registerChromePackage
#
# Enter a chrome package into the installed-chrome.txt file
#-------------------------------------------------------------------------------
sub registerChromePackage($$$$$$)
{
my($jar_file, $file_path, $chrome_dir, $jar_hash, $chrome_type, $pkg_name) = @_;
my($manifest_subdir) = $jar_file;
$manifest_subdir =~ s/:/\//g;
if (index($manifest_subdir, "-unix") == -1 && index($manifest_subdir, "-win") == -1) {
my($chrome_entry);
if ($main::options{use_jars}) {
$chrome_entry = "$chrome_type,install,url,jar:resource:/chrome/$manifest_subdir!/$chrome_type/$pkg_name";
} else {
$manifest_subdir =~ s/\.jar$//;
$chrome_entry = "$chrome_type,install,url,resource:/chrome/$manifest_subdir/$chrome_type/$pkg_name";
}
# print "Entering $chrome_entry in installed-chrome.txt\n";
# ensure chrome_dir exists
mkpath($chrome_dir);
my($inst_chrome) = ${chrome_dir}.":installed-chrome.txt";
if (open(CHROMEFILE, "<$inst_chrome")) {
while (<CHROMEFILE>) {
chomp;
if ($_ eq $chrome_entry) {
# $chrome_entry already appears in installed-chrome.txt file
# just update the mod date
my $now = time;
utime($now, $now, $inst_chrome) || die "Error: Couldn't touch $inst_chrome";
print "+++ updating chrome $inst_chrome\n+++\t\t$chrome_entry\n";
close(CHROMEFILE) || die "Error: can't close $inst_chrome: $!";
return 0;
}
}
close(CHROMEFILE) || die "Error: can't close $inst_chrome: $!";
}
open(CHROMEFILE, ">>${inst_chrome}") || die "Error: Failed to open $inst_chrome\n";
print(CHROMEFILE "${chrome_entry}\n");
close(CHROMEFILE) || die "Error: Failed to close $inst_chrome\n";
print "+++ adding chrome $inst_chrome\n+++\t\t$chrome_entry\n";
}
}
#-------------------------------------------------------------------------------
# Create or add to a jar file from a jar.mn file.
# Both arguments are relative to the mozilla root dir.
#
#
#-------------------------------------------------------------------------------
sub CreateJarFromManifest($$$)
{
my($jar_man_path, $dest_path, $jars) = @_;
if ($main::options{chrome_jars}) {
print "Jarring from $jar_man_path\n";
}
if ($main::options{chrome_files}) {
print "Installing files from $jar_man_path\n";
}
$jar_man_path = full_path_to($jar_man_path);
$dest_path = full_path_to($dest_path);
# if the jars hash is empty, nuke installed-chrome.txt
if (! scalar(%$jars))
{
print "Nuking installed-chrome.txt\n";
my($installed_chrome) = $dest_path.":installed-chrome.txt";
# unlink $installed_chrome;
}
my $jar_man_dir = "";
my $jar_man_file = "";
if ($jar_man_path =~ /(.+):([^:]+)$/)
{
$jar_man_dir = $1; # no trailing :
$jar_man_file = $2;
}
# Keep a hash of jar files, keyed on relative jar path (e.g. "packages/core.jar")
# Entries are open Archive::Zips (if zipping), and installed-chrome entries.
my($jar_id) = ""; # Current foo/bar.jar from jar.mn file
my($jar_file) = ""; # relative path to jar file (from $dest_path), with mac separators
my($full_jar_path);
open(FILE, "<$jar_man_path") || die "Error: could not open \"$jar_man_path\": $!";
while (<FILE>)
{
my($line) = $_;
chomp($line);
# print "$line\n";
if ($line =~ /^\s*\#.*$/) { # skip comments
next;
}
if ($line =~/^([\w\d.\-\_\\\/]+)\:\s*$/) # line start jar file entries
{
$jar_id = $1;
$jar_file = $jar_id;
$jar_file =~ s|/|:|g; # slash to colons
$full_jar_path = $dest_path.":".$jar_file;
setupJarFile($jar_id, $dest_path, $jars);
}
elsif ($line =~ /^(\+?)\s+([\w\d.\-\_\\\/]+)\s*(\([\w\d.\-\_\\\/]+\))?$\s*/) # jar file entry
{
my($override) = ($1 eq "+");
my($file_dest) = $2;
my($file_src) = $3;
if ($file_src) {
$file_src = substr($file_src, 1, -1); #strip the ()
} else {
$file_src = $file_dest;
}
$file_src =~ s|/|:|g;
if ($jar_file ne "") # if jar is open, add to jar
{
if ($file_dest =~ /([\w\d.\-\_]+)\/([\w\d.\-\_\\\/]+)contents.rdf/)
{
my $chrome_type = $1;
my $pkg_name = $2;
registerChromePackage($jar_file, $file_dest, $dest_path, $jars, $chrome_type, $pkg_name);
}
addToJarFile($jar_id, $jar_man_dir, $file_src, $full_jar_path, $file_dest, $override, $jars);
}
else
{
die "Error: bad jar.mn format at $line\n";
}
}
elsif ($line =~ /^\s*$/ ) # blank line
{
if ($jar_file ne "") #if a jar file is open, close it
{
closeJarFile($full_jar_path, $jars);
$jar_file = "";
$full_jar_path = "";
}
}
}
close(FILE);
if ($jar_file ne "") #if a jar file is open, close it
{
closeJarFile($full_jar_path, $jars);
}
}
1;

View File

@@ -1,228 +0,0 @@
#!perl -w
package Moz::MacCVS;
# package Mac::Apps::MacCVS; this should really be the name of the package
# but due to our directory hierarchy in mozilla, I am not doing it
require 5.004;
require Exporter;
use strict;
use Exporter;
use vars qw($VERSION @ISA @EXPORT);
use Cwd;
use File::Basename;
use Mac::StandardFile;
use Mac::AppleEvents;
use Mac::AppleEvents::Simple;
@ISA = qw(Exporter);
@EXPORT = qw(new describe checkout update);
$VERSION = "1.00";
# If you want to understand the gobbldeygook that's used to build Apple Events,
# you should start by reading the AEGizmos documentation.
# Architecture:
# cvs session object:
# name - session name
# session_file - session file
#
#
my($last_error) = 0;
my($gAppSig) = 'Mcvs'; # MacCVS Pro
#
# utility routines
#
sub _checkForEventError($)
{
my($evt) = @_;
if ($evt->{ERRNO} != 0)
{
print STDERR "Error. Script returned '$evt->{ERROR} (error $evt->{ERRNO})\n";
$last_error = $evt->{ERRNO};
return 0;
}
return 1; # success
}
#
# Session object methods
#
sub new
{
my ( $proto, $session_file) = @_;
my $class = ref($proto) || $proto;
my $self = {};
if ( defined($session_file) && ( -e $session_file) )
{
$self->{"name"} = basename( $session_file );
$self->{"session_file"} = $session_file;
bless $self, $class;
return $self;
}
else
{
print STDERR "MacCVS->new cvs file < $session_file > does not exist\n";
return;
}
}
# makes sure that the session is open
# assertSessionOpen()
# returns 1 on success
sub assertSessionOpen()
{
my ($self) = shift;
$last_error = 0;
my($prm) =
q"'----':obj {form:name, want:type(alis), seld:TEXT(@), from:'null'()}";
my($evt) = do_event(qw/aevt odoc/, $gAppSig, $prm, $self->{session_file});
return _checkForEventError($evt);
}
# prints the cvs object, used mostly for debugging
sub describe
{
my($self) = shift;
$last_error = 0;
print "MacCVS:: name: ", $self->{name}, " session file: ", $self->{session_file}, "\n";
}
# checkout( self, module, revision, date)
# MacCVS checkout command
# returns 1 on success.
sub checkout()
{
my($self, $module, $revision, $date ) = @_;
unless( defined ($module) ) { $module = ""; } # get rid of the pesky undefined warnings
unless( defined ($revision) ) { $revision = ""; }
unless( defined ($date) ) { $date = ""; }
$last_error = 0;
$self->assertSessionOpen() || die "Error: failed to open MacCVS session file at $self->{session_file}\n";
my($revstring) = ($revision ne "") ? $revision : "(none)";
my($datestring) = ($date ne "") ? $date : "(none)";
print "Checking out $module with revision $revstring, date $datestring\n";
my($prm) =
q"'----':obj {form:name, want:type(docu), seld:TEXT(@), from:'null'()}, ".
q"modl:'TEXT'(@), tagr:'TEXT'(@), tagd:'TEXT'(@) ";
my($evt) = do_event(qw/MCvs cout/, $gAppSig, $prm, $self->{name}, $module, $revision, $date);
return _checkForEventError($evt);
}
# update( self, branch tag, list of paths)
# MacCVS udate command
# returns 1 on success.
# NOTE: MacCVS Pro does not correctly support this stuff yet (as of version 2.7d5).
sub update()
{
my($self, $branch, $paths ) = @_;
$last_error = 0;
$self->assertSessionOpen() || die "Error: failed to open MacCVS session file at $self->{session_file}\n";
if ($branch eq "HEAD") {
$branch = "";
}
my($paths_list) = "";
my($path);
foreach $path (@$paths)
{
if ($paths_list ne "") {
$paths_list = $paths_list.", ";
}
$paths_list = $paths_list."Ò".$path."Ó";
}
my($prm) =
q"'----':obj {form:name, want:type(docu), seld:TEXT(@), from:'null'()}, ".
q"tagr:'TEXT'(@), tFls:[";
$prm = $prm.$paths_list."]";
my($evt) = do_event(qw/MCvs updt/, $gAppSig, $prm, $self->{name}, $branch);
return _checkForEventError($evt);
};
sub getLastError()
{
return $last_error;
}
1;
=pod
=head1 NAME
MacCVS - Interface to MacCVS
=head1 SYNOPSIS
use MacCVS;
$session = MacCVS->new( <session_file_path>) || die "cannot create session";
$session->checkout([module] [revision] [date]) || die "Could not check out";
=head1 DESCRIPTION
This is a MacCVS interface for talking to MacCVS Pro client.
MacCVSSession is the class used to manipulate the session
=item new
MacCVS->new( <cvs session file path>);
Creates a new session. Returns undef on failure.
=item checkout( <module> [revision] [date] )
cvs checkout command. Revision and date are optional
returns 0 on failure
=cut
=head1 SEE ALSO
=over
=item MacCVS Home Page
http://www.maccvs.org/
=back
=head1 AUTHORS
Aleks Totic atotic@netscape.com
Simon Fraser sfraser@netscape.com
=cut
__END__

View File

@@ -1,603 +0,0 @@
=head1 NAME
B<Moz> - routines for automating CodeWarrior builds, and some extra-curricular
activities related to building Mozilla
=head1 SYNOPSIS
use Moz;
OpenErrorLog(":::BuildLog");
StopForErrors();
$Moz::QUIET = 1;
InstallFromManifest(":projects:MANIFEST", $dist_dir);
BuildProjectClean(":projects:SomeProject.mcp", "SomeTarget");
MakeAlias(":projects:SomeProject.shlb", $dist_dir);
DontStopForErrors();
BuildProject(":projects:SomeOtherProject.mcp", "SomeTarget");
=head1 DESCRIPTION
B<Moz> comprises the routines needed to slap CodeWarrior around, force it
to build a sequence of projects, report the results, and a few other things.
This module should only contain functions that are generic to any build,
not just the Mozilla build.
=cut
package Moz::Moz;
require Exporter;
use Cwd;
use File::Copy;
use File::Path;
use File::Basename;
use Mac::Types;
use Mac::Events;
use Mac::Processes;
use ExtUtils::Manifest 'maniread';
use Moz::CodeWarriorLib;
@ISA = qw(Exporter);
@EXPORT = qw( LaunchCodeWarrior
GetCodeWarriorRelativePath
current_directory
full_path_to
DoBuildProject
ImportXMLProject
ExportProjectToXML
OpenErrorLog
MakeAlias
GetFileModDate
StopForErrors
DontStopForErrors
InstallFromManifest
InstallResources
RedirectOutputToFile
Delay
ActivateApplication
IsProcessRunning);
@EXPORT_OK = qw(CloseErrorLog QUIET);
sub current_directory()
{
my $current_directory = cwd();
chop($current_directory) if ( $current_directory =~ m/:$/ );
return $current_directory;
}
sub full_path_to($)
{
my ($path) = @_;
if ( $path =~ m/^[^:]+$/ )
{
$path = ":" . $path;
}
if ( $path =~ m/^:/ )
{
$path = current_directory() . $path;
}
return $path;
}
$logging = 0;
$recent_errors_file = "";
$stop_on_1st_error = 1;
$QUIET = 0;
=head2 Logging all the errors and warnings - C<OpenErrorLog($log_file)>, C<CloseErrorLog()>
The warnings and errors generated in the course of building projects can be logged to a file.
Tinderbox uses this facility to show why a remote build failed.
Logging is off by default.
Start logging at any point in your build process with C<OpenErrorLog($log_file)>.
Stop with C<CloseErrorLog()>.
You never need to close the log explicitly, unless you want to just log a couple of projects in the middle of a big list.
C<CloseErrorLog()> is not exported by default.
=cut
sub CloseErrorLog()
{
if ( $logging )
{
close(ERROR_LOG);
$logging = 0;
StopForErrors() if $stop_on_1st_error;
}
}
sub OpenErrorLog($)
{
my ($log_file) = @_;
CloseErrorLog();
if ( $log_file )
{
$log_file = full_path_to($log_file);
open(ERROR_LOG, ">$log_file") || die "Error: Can't open $log_file\n";
MacPerl::SetFileInfo("CWIE", "TEXT", $log_file);
$log_file =~ m/.+:(.+)/;
$recent_errors_file = full_path_to("$1.part");
$logging = 1;
}
}
=head2 Stopping before it's too late - C<StopForErrors()>, C<DontStopForErrors()>
When building a long list of projects, you decide whether to continue building subsequent projects when one fails.
By default, your build script will C<die> after the first project that generates an error while building.
Change this behavior with C<DontStopForErrors()>.
Re-enable it with C<StopForErrors()>.
=cut
sub StopForErrors()
{
$stop_on_1st_error = 1;
# Can't stop for errors unless we notice them.
# Can't notice them unless we are logging.
# If the user didn't explicitly request logging, log to a temporary file.
if ( ! $recent_errors_file )
{
OpenErrorLog("${TMPDIR}BuildResults");
}
}
sub DontStopForErrors()
{
$stop_on_1st_error = 0;
}
sub log_message($)
{
if ( $logging )
{
my ($message) = @_;
print ERROR_LOG $message;
}
}
sub log_message_with_time($)
{
if ( $logging )
{
my ($message) = @_;
my $time_stamp = localtime();
log_message("$message ($time_stamp)\n");
}
}
sub log_recent_errors($)
{
my ($project_name) = @_;
my $found_errors = 0;
if ( $logging )
{
open(RECENT_ERRORS, "<$recent_errors_file");
while( <RECENT_ERRORS> )
{
if ( /^Error/ || /^CouldnÕt find project file/ || /^Link Error/ )
{
# if (!$found_errors)
# print $_;
$found_errors = 1;
}
print ERROR_LOG $_;
}
close(RECENT_ERRORS);
unlink("$recent_errors_file");
}
if ( $stop_on_1st_error && $found_errors )
{
print ERROR_LOG "### Build failed.\n";
die "### Errors encountered building \"$project_name\".\n";
}
}
sub DoBuildProject($$$)
{
my ($project_path, $target_name, $clean_build) = @_;
$project_path = full_path_to($project_path);
# $project_path =~ m/.+:(.+)/;
# my $project_name = $1;
log_message_with_time("### Building \"$project_path\"");
# Check that the given project exists
if (! -e $project_path)
{
print ERROR_LOG "### Build failed.\n";
die "### Can't find project file \"$project_path\".\n";
}
print "Building \"$project_path\[$target_name\]\"\n";
$had_errors = Moz::CodeWarriorLib::build_project(
$project_path, $target_name, $recent_errors_file, $clean_build
);
WaitNextEvent();
# $had_errors =
#MacPerl::DoAppleScript(<<END_OF_APPLESCRIPT);
# tell (load script file "$CodeWarriorLib") to BuildProject("$project_path", "$project_name", "$target_name", "$recent_errors_file", $clean_build)
#END_OF_APPLESCRIPT
# Append any errors to the globally accumulated log file
# if ( $had_errors ) # Removed this test, because we want warnings, too. -- jrm
{
log_recent_errors($project_path);
}
}
sub ImportXMLProject($$)
{
my ($xml_path, $project_path) = @_;
# my ($codewarrior_ide_name) = Moz::CodeWarriorLib::getCodeWarriorIDEName();
# my $ascript = <<EOS;
# tell application "$codewarrior_ide_name"
# make new (project document) as ("$project_path") with data ("$xml_path")
# end tell
#EOS
# print $ascript."\n";
# my($result) = MacPerl::DoAppleScript($ascript);
# unless ($result) { die "Error: ImportXMLProject AppleScript failed $^E $result\n"; }
#
my($import_error) = Moz::CodeWarriorLib::import_project($xml_path, $project_path);
if ($import_error ne "") {
die "Error: ImportXMLProject failed with error $import_error\n";
}
}
sub ExportProjectToXML($$)
{
my ($project_path, $xml_path) = @_;
my (@suffix_list) = (".mcp");
my ($project_name, $project_dir, $suffix) = fileparse($project_path, @suffix_list);
if ($suffix eq "") { die "Project: $project_path doesn't look like a project file.\n"; }
if (-e $xml_path) {
print "$xml_path exists - not exporting $project_path\n";
}
else {
print "Exporting $project_path to $xml_path\n";
my($export_error) = Moz::CodeWarriorLib::export_project($project_path, $xml_path);
if ($export_error ne "") {
die "Error: export_project failed with error '$export_error'\n";
}
if (! -e $xml_path) {
die "Error: XML export to $xml_path failed\n";
}
}
}
=head2 Miscellaneous
C<MakeAlias($old_file, $new_file)> functions like C<symlink()>, except with better argument defaulting and more explicit error messages.
=cut
sub MakeAlias($$)
{
my ($old_file, $new_file) = @_;
# if the directory to hold $new_file doesn't exist, create it
if ( ($new_file =~ m/(.+:)/) && !-d $1 )
{
mkpath($1);
}
# if a leaf name wasn't specified for $new_file, use the leaf from $old_file
if ( ($new_file =~ m/:$/) && ($old_file =~ m/.+:(.+)/) )
{
$new_file .= $1;
}
my $message = "Can't create a Finder alias (at \"$new_file\")\n for \"$old_file\"; because ";
die "Error: $message \"$old_file\" doesn't exist.\n" unless -e $old_file;
die "Error: $message I won't replace an existing (non-alias) file with an alias.\n" if ( -e $new_file && ! -l $new_file );
# now: $old_file exists; $new_file doesn't (or else, is an alias already)
if ( -l $new_file )
{
# ...then see if it already points to $old_file
my $current_target = full_path_to(readlink($new_file));
my $new_target = full_path_to($old_file);
return if ( $current_target eq $new_target );
# if the desired alias already exists and points to the right thing, then we're done
unlink $new_file;
}
symlink($old_file, $new_file) || die "Error: $message symlink returned an unexpected error.\n";
}
=pod
C<InstallFromManifest()>
=cut
sub InstallFromManifest($;$$)
{
my ($manifest_file, $dest_dir, $flat) = @_;
$flat = 0 unless defined($flat); # if $flat, all rel. paths in MANIFEST get aliased to the root of $dest_dir
$dest_dir ||= ":";
$manifest_file =~ m/(.+):/;
my $source_dir = $1;
chop($dest_dir) if $dest_dir =~ m/:$/;
#Mac::Events->import();
WaitNextEvent();
if ($flat)
{
print "Doing manifest on \"$manifest_file\" FLAT\n" unless $QUIET;
}
else
{
print "Doing manifest on \"$manifest_file\"\n" unless $QUIET;
}
my $read = maniread(full_path_to($manifest_file));
foreach $file (keys %$read)
{
next unless $file;
$subdir = ":";
if (!$flat && ($file =~ /:.+:/ ))
{
$subdir = $&;
}
$file = ":$file" unless $file =~ m/^:/;
MakeAlias("$source_dir$file", "$dest_dir$subdir");
}
}
=pod
C<InstallResources()>
=cut
# parameters are path to MANIFEST file, destination dir, true (to make copies) or false (to make aliases)
sub InstallResources($;$;$)
{
my ($manifest_file, $dest_dir, $copy_files) = @_;
$dest_dir ||= ":";
mkpath($dest_dir) if !-d $dest_dir;
$manifest_file =~ m/(.+):/;
my $source_dir = $1;
chop($dest_dir) if $dest_dir =~ m/:$/;
WaitNextEvent();
print "Installing resources from \"$manifest_file\"\n" unless $QUIET;
my $read = maniread(full_path_to($manifest_file));
foreach $file (keys %$read)
{
next unless $file;
if ($copy_files)
{
copy("$source_dir:$file", "$dest_dir:$file");
}
else
{
MakeAlias("$source_dir:$file", "$dest_dir:$file");
}
}
}
#//--------------------------------------------------------------------------------------------------
#// Delay
#//--------------------------------------------------------------------------------------------------
sub Delay($)
{
my ($delay_seconds) = @_;
$now = time;
$exit_time = $now + $delay_seconds;
while ($exit_time > $now) {
$now = time;
}
}
#//--------------------------------------------------------------------------------------------------
#// GetFileModDate
#//--------------------------------------------------------------------------------------------------
sub GetFileModDate($)
{
my($filePath)=@_;
my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
$atime,$mtime,$ctime,$blksize,$blocks) = stat($filePath);
return $mtime;
}
#//--------------------------------------------------------------------------------------------------
#// LaunchCodeWarrior
#//--------------------------------------------------------------------------------------------------
sub LaunchCodeWarrior($)
{
my($idepath_file) = @_; # full path to IDE location file
my($cur_dir) = cwd();
# this both launches and writes the IDE path file
Moz::CodeWarriorLib::activate($idepath_file);
chdir($cur_dir);
}
#//--------------------------------------------------------------------------------------------------
#// GetCodeWarriorRelativePath
#//--------------------------------------------------------------------------------------------------
sub GetCodeWarriorRelativePath($)
{
my($rel_path) = @_;
return Moz::CodeWarriorLib::getCodeWarriorPath($rel_path);
}
#//--------------------------------------------------------------------------------------------------
#// RedirectOutputToFile
#//--------------------------------------------------------------------------------------------------
sub RedirectOutputToFile($)
{
my($log_file) = @_;
# ensure that folders in the path exist
my($logdir) = "";
my($logfile) = $log_file;
if ($log_file =~ /(.+?:)([^:]+)$/) # ? for non-greedy match
{
$logdir = $1;
$logfile = $2;
mkpath($logdir);
}
print "Output is now being redirected to the file '$log_file'\n";
open(STDOUT, "> $log_file") || die "Can't redirect stdout";
open(STDERR, ">&STDOUT") || die "Can't dup stdout";
select(STDERR); $| = 1; # make unbuffered
select(STDOUT); $| = 1; # make unbuffered
MacPerl::SetFileInfo("CWIE", "TEXT", $log_file);
}
#//--------------------------------------------------------------------------------------------------
#// ActivateApplication
#//--------------------------------------------------------------------------------------------------
sub ActivateApplication($)
{
my ($appSignature) = @_;
my ($psi, $found);
my ($appPSN);
$found = 0;
foreach $psi (values(%Process))
{
if ($psi->processSignature() eq $appSignature)
{
$appPSN = $psi->processNumber();
$found = 1;
last;
}
}
if ($found == 0 || SameProcess($appPSN, GetFrontProcess()))
{
return;
}
SetFrontProcess($appPSN);
while (GetFrontProcess() != $appPSN)
{
WaitNextEvent();
}
}
#//--------------------------------------------------------------------------------------------------
#// IsProcessRunning
#//--------------------------------------------------------------------------------------------------
sub IsProcessRunning($)
{
my($processName, $psn, $psi) = @_;
while ( ($psn, $psi) = each(%Process) ) {
if ($psi->processName eq $processName) { return 1; }
}
return 0;
}
1;
=head1 AUTHORS
Scott Collins <scc@netscape.com>, Simon Fraser <sfraser@netscape.com>, Chris Yeh <cyeh@netscape.com>
=head1 SEE ALSO
BuildMozillaDebug.pl (et al), BuildList.pm, CodeWarriorLib (an AppleScript library)
=head1 COPYRIGHT
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 Communicator client code, released
March 31, 1998.
The Initial Developer of the Original Code is Netscape
Communications Corporation. Portions created by Netscape are
Copyright (C) 1998-1999 Netscape Communications Corporation. All
Rights Reserved.
Contributor(s):
=cut

View File

@@ -1,272 +0,0 @@
package Moz::Prefs;
require 5.004;
require Exporter;
# Package that attempts to read a file from the Preferences folder,
# and get build settings out of it
use strict;
use Exporter;
use File::Path;
use Mac::Files;
use vars qw(@ISA @EXPORT);
@ISA = qw(Exporter);
@EXPORT = qw(ReadMozUserPrefs);
#-------------------------------------------------------------------------------
#
# GetPrefsFolder
#
#-------------------------------------------------------------------------------
sub GetPrefsFolder()
{
my($prefs_folder) = FindFolder(kOnSystemDisk, kPreferencesFolderType, 1);
return $prefs_folder.":Mozilla build prefs";
}
#-------------------------------------------------------------------------------
#
# SetArrayValue
#
#-------------------------------------------------------------------------------
sub SetArrayValue($$$)
{
my($array_ref, $index1, $index2) = @_;
my($index);
foreach $index (@$array_ref)
{
if ($index->[0] eq $index1)
{
$index->[1] = $index2;
return 1;
}
}
return 0;
}
#-------------------------------------------------------------------------------
#
# WriteDefaultPrefsFile
#
#-------------------------------------------------------------------------------
sub WriteDefaultPrefsFile($)
{
my($file_path) = @_;
my($file_contents);
$file_contents = <<'EOS';
% You can use this file to customize the Mozilla build system.
% The following kinds of lines are allowable:
% Comment lines, which start with a '%' in the first column
% Lines which modify the default build settings. For the list of flags,
% see MozBuildFlags.pm. Examples are:
%
% build pull 0 % don't pull
% options mng 1 % turn mng on
%
% Line containing the special 'buildfrom' flag, which specifies
% where to start the build. Example:
%
% buildfrom nglayout % where to start the build
%
% Lines which specify the location of the files used to store paths
% to the CodeWarrior IDE, and the MacCVS Pro session file. Note quoting
% of paths containing whitespace. Examples:
%
% filepath idepath ::codewarrior.txt
% filepath sessionpath ":Some folder:MacCVS session path.txt"
%
% Lines which modify the build settings like %main::DEBUG.
% Any lines which do not match either of the above are assumed
% to set variables on $main::. Examples:
%
% MOZILLA_OFFICIAL 1
%
EOS
$file_contents =~ s/%/#/g;
local(*PREFS_FILE);
open(PREFS_FILE, "> $file_path") || die "Could not write default prefs file\n";
print PREFS_FILE ($file_contents);
close(PREFS_FILE);
MacPerl::SetFileInfo("McPL", "TEXT", $file_path);
}
#-------------------------------------------------------------------------------
#
# HandlePrefSet
#
#-------------------------------------------------------------------------------
sub HandlePrefSet($$$$)
{
my($flags, $name, $value, $desc) = @_;
if (SetArrayValue($flags, $name, $value)) {
print "Prefs set $desc flag '$name' to '$value'\n";
} else {
die "$desc setting '$name' is not a valid option\n";
}
}
#-------------------------------------------------------------------------------
#
# HandleBuildFromPref
#
#-------------------------------------------------------------------------------
sub HandleBuildFromPref($$)
{
my($build_array, $name) = @_;
my($setting) = 0;
my($index);
foreach $index (@$build_array)
{
if ($index->[0] eq $name) {
$setting = 1;
}
$index->[1] = $setting;
}
if ($setting == 1) {
print "Building from $name onwards, as specified by prefs\n";
} else {
printf "Failed to find buildfrom setting '$name'\n";
}
}
#-------------------------------------------------------------------------------
#
# ReadPrefsFile
#
#-------------------------------------------------------------------------------
sub ReadPrefsFile($$$$$)
{
my($file_path, $build_flags, $options_flags, $filepath_flags, $create_if_missing) = @_;
local(*PREFS_FILE);
if (open(PREFS_FILE, "< $file_path"))
{
print "Reading build prefs from '$file_path'\n";
while (<PREFS_FILE>)
{
my($line) = $_;
chomp($line);
if ($line =~ /^\#/ || $line =~ /^\s*$/) { # ignore comments and empty lines
next;
}
if (($line =~ /^\s*([^#\s]+)\s+([^#\s]+)\s+\"(.+)\"(\s+#.+)?/) ||
($line =~ /^\s*([^#\s]+)\s+([^#\s]+)\s+\'(.+)\'(\s+#.+)?/) ||
($line =~ /^\s*([^#\s]+)\s+([^#\s]+)\s+([^#\s]+)(\s+#.+)?/))
{
my($array_name) = $1;
my($option_name) = $2;
my($option_value) = $3;
# print "Read '$array_name' '$option_name' '$option_value'\n";
if ($array_name eq "build")
{
HandlePrefSet($build_flags, $option_name, $option_value, "Build");
}
elsif ($array_name eq "options")
{
HandlePrefSet($options_flags, $option_name, $option_value, "Options");
}
elsif ($array_name eq "filepath" && $option_name && $option_value)
{
HandlePrefSet($filepath_flags, $option_name, $option_value, "Filepath");
}
else
{
print "Unknown pref option at $line\n";
}
}
elsif ($line =~ /^\s*buildfrom\s+([^#\s]+)(\s+#.+)?/)
{
my($build_start) = $1;
HandleBuildFromPref($build_flags, $build_start);
}
elsif ($line =~ /^\s*([^#\s]+)\s+([^#\s]+)(\s+#.+)?/)
{
my($build_var) = $1;
my($var_setting) = $2;
print "Setting \$main::$build_var to $var_setting\n";
eval "\$main::$build_var = \"$var_setting\"";
}
else
{
print "Unrecognized input line at $line\n";
}
}
close(PREFS_FILE);
}
elsif ($create_if_missing)
{
print "No prefs file found at $file_path; using defaults\n";
my($folder_path) = $file_path;
$folder_path =~ s/[^:]+$//;
mkpath($folder_path);
WriteDefaultPrefsFile($file_path);
}
}
#-------------------------------------------------------------------------------
#
# ReadMozUserPrefs
#
#-------------------------------------------------------------------------------
sub ReadMozUserPrefs($$$$)
{
my($prefs_file_name, $build_flags, $options_flags, $filepath_flags) = @_;
if ($prefs_file_name eq "") { return; }
# if local prefs exist, just use those. Othewise, look in the prefs folder
if (-e $prefs_file_name)
{
# read local prefs
ReadPrefsFile($prefs_file_name, $build_flags, $options_flags, $filepath_flags, 0);
}
else
{
# first read prefs folder prefs
my($prefs_path) = GetPrefsFolder();
$prefs_path .= ":$prefs_file_name";
ReadPrefsFile($prefs_path, $build_flags, $options_flags, $filepath_flags, 1);
}
}
1;

View File

@@ -1,932 +0,0 @@
#!/usr/bin/perl
#
# 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) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
# Simon Fraser <sfraser@netscape.com>
#
package Moz::ProjectXML;
require 5.004;
require Exporter;
use strict;
use Exporter;
use Cwd;
use XML::DOM;
use vars qw(@ISA @EXPORT);
@ISA = qw(Exporter);
@EXPORT = qw(
ParseXMLDocument
DisposeXMLDocument
WriteXMLDocument
CleanupPro5XML
GetTargetsList
CloneTarget
SetAsSharedLibraryTarget
SetAsStaticLibraryTarget
AddTarget
RemoveTarget
GetTargetSetting
SetTargetSetting
getChildElementTextContents
);
#--------------------------------------------------------------------------------------------------
# A module for reading, manipulating, and writing XML-format CodeWarrior project files.
#
# Sample usage:
#
# use ProjectXML;
#
# my $doc = ProjectXML::ParseXMLDocument("Test.mcp.xml");
# ProjectXML::CloneTarget($doc, "Test.shlb", "Test.lib");
# ProjectXML::SetAsStaticLibraryTarget($doc, "Test.lib", "TestOutput.lib");
# ProjectXML::WriteXMLDocument($doc, "Test_out.xml");
# ProjectXML::DisposeXMLDocument($doc);
#
#--------------------------------------------------------------------------------------------------
#//--------------------------------------------------------------------------------------------------
#// ParseXMLDocument
#// Note that the caller must call DisposeXMLDocument on the returned doc
#//--------------------------------------------------------------------------------------------------
sub ParseXMLDocument($)
{
my($doc_path) = @_;
my $parser = new XML::DOM::Parser(ErrorContext => 2);
my $doc = $parser->parsefile($doc_path);
return $doc;
}
#//--------------------------------------------------------------------------------------------------
#// DisposeXMLDocument
#// Needed to avoid memory leaks - cleanup circular references for garbage collection
#//--------------------------------------------------------------------------------------------------
sub DisposeXMLDocument($)
{
my($doc) = @_;
$doc->dispose();
}
#//--------------------------------------------------------------------------------------------------
#// WriteXMLDocument
#//--------------------------------------------------------------------------------------------------
sub _pro5_tag_compression($$)
{
return 1; # Pro 5 is broken and can't import XML with <foo/> style tags
}
sub _pro6plus_tag_compression($$)
{
return 0; # Pro 6 can deal with empty XML tags like <foo/>
}
sub WriteXMLDocument($$$)
{
my($doc, $file_path, $ide_version) = @_;
if ($ide_version eq "4.0")
{
XML::DOM::setTagCompression(\&_pro5_tag_compression);
}
else
{
XML::DOM::setTagCompression(\&_pro6plus_tag_compression);
}
$doc->printToFile($file_path);
}
#//--------------------------------------------------------------------------------------------------
#// CleanupPro5XML
#// XML Projects exported by Pro 5 contain garbage data under the MWMerge_MacOS_skipResources
#// setting. This routine cleans this up, saving the result to a new file
#//--------------------------------------------------------------------------------------------------
sub CleanupPro5XML($$)
{
my($xml_path, $out_path) = @_;
local(*XML_FILE);
open(XML_FILE, "< $xml_path") || die "Error: failed to open file $xml_path\n";
local(*CLEANED_FILE);
open(CLEANED_FILE, "> $out_path") || die "Error: failed to open file $out_path for writing\n";
my $in_skip_resources_settings = 0;
while(<XML_FILE>)
{
my($line) = $_;
if ($line =~ /^<\?codewarrior/) # is processing inst line
{
my $test_line = $line;
chomp($test_line);
my $out_line = $test_line;
if ($test_line =~ /^<\?codewarrior\s+exportversion=\"(.+)\"\s+ideversion=\"(.+)\"\s*\?>$/)
{
my $export_version = $1;
my $ide_version = $2;
$ide_version = "4.0_mozilla"; # pseudo IDE version so we know we touched it
$out_line = "<?codewarrior exportversion=\"".$export_version."\" ideversion=\"".$ide_version."\"?>";
}
print CLEANED_FILE "$out_line\n";
next;
}
if ($line =~ /MWMerge_MacOS_skipResources/)
{
$in_skip_resources_settings = 1;
print CLEANED_FILE "$line";
}
elsif($in_skip_resources_settings && $line =~ /<!-- Settings for/)
{
# leaving bad settings lines. Write closing tag
print CLEANED_FILE " <!-- Corrupted setting entries removed by script -->\n";
print CLEANED_FILE " </SETTING>\n\n";
print CLEANED_FILE "$line";
$in_skip_resources_settings = 0;
}
elsif (!$in_skip_resources_settings)
{
print CLEANED_FILE "$line";
}
}
close(XML_FILE);
close(CLEANED_FILE);
}
#--------------------------------------------------------------------------------------------------
# SniffProjectXMLIDEVersion
#
#--------------------------------------------------------------------------------------------------
sub SniffProjectXMLIDEVersion($)
{
my($xml_path) = @_;
my $found_version = "";
local(*XML_FILE);
open(XML_FILE, "< $xml_path") || die "Error: failed to open file $xml_path\n";
while(<XML_FILE>)
{
my($line) = $_;
chomp($line);
if ($line =~ /^<\?codewarrior/) # is processing inst line
{
unless ($line =~ /^<\?codewarrior\s+exportversion=\"(.+)\"\s+ideversion=\"(.+)\"\s*\?>$/)
{
die "Error: Failed to find ideversion in $xml_path in line $line\n";
}
my $export_version = $1;
my $ide_version = $2;
$found_version = $ide_version;
last;
}
}
close(XML_FILE);
return $found_version;
}
#//--------------------------------------------------------------------------------------------------
#// GetTargetsList
#// Returns an array of target names
#//--------------------------------------------------------------------------------------------------
sub GetTargetsList($)
{
my($doc) = @_;
my $nodes = $doc->getElementsByTagName("TARGET");
my $n = $nodes->getLength;
my @target_names;
for (my $i = 0; $i < $n; $i++)
{
my ($node) = $nodes->item($i);
my($target_name) = getChildElementTextContents($node, "NAME");
push(@target_names, $target_name);
}
return @target_names;
}
#//--------------------------------------------------------------------------------------------------
#// CloneTarget
#// Clone the named target, renaming it to 'new_name'
#//--------------------------------------------------------------------------------------------------
sub CloneTarget($$$)
{
my($doc, $target_name, $new_name) = @_;
my $target_node = getTargetNode($doc, $target_name);
# clone here
my $target_clone = $target_node->cloneNode(1); # deep clone
# -- munge target settings --
# set the target name field
setChildElementTextContents($doc, $target_clone, "NAME", $new_name);
# set the targetname pref
setTargetNodeSetting($doc, $target_clone, "Targetname", $new_name);
# -- insert new target subtree --
my $target_list = $target_node->getParentNode();
$target_list->appendChild($target_clone);
# -- now add to targetorder --
my (@target_order_nodes) = getChildOfDocument($doc, "TARGETORDER");
my $target_order = @target_order_nodes[0];
my $new_order = $doc->createElement("ORDEREDTARGET");
my $order_name = $doc->createElement("NAME");
$new_order->appendChild($order_name);
setChildElementTextContents($doc, $new_order, "NAME", $new_name);
$target_order->appendChild($new_order);
}
#//--------------------------------------------------------------------------------------------------
#// SetAsSharedLibraryTarget
#//
#//--------------------------------------------------------------------------------------------------
sub SetAsSharedLibraryTarget($$$)
{
my($doc, $target_name, $output_name) = @_;
my $target_node = getTargetNode($doc, $target_name);
setTargetNodeSetting($doc, $target_node, "MWProject_PPC_type", "SharedLibrary");
setTargetNodeSetting($doc, $target_node, "MWProject_PPC_filetype", "1936223330"); #'shlb'
setTargetNodeSetting($doc, $target_node, "MWProject_PPC_outfile", $output_name);
}
#//--------------------------------------------------------------------------------------------------
#// AddFileToTarget
#//
#// Add a file to the specified target(s).
#//
#//--------------------------------------------------------------------------------------------------
sub AddFileToTarget($$$)
{
my($doc, $target_list, $file_name) = @_;
# the file must be added in 3 places:
# 1. in <TARGET><FILELIST><FILE> (with linkage flags if necessary)
# 2. in <TARGET><LINKORDER><FILEREF>
# 3. in <GROUPLIST><GROUP><FILEREF>
die "Write me\n";
}
#//--------------------------------------------------------------------------------------------------
#// RemoveFileFromTarget
#//
#// Remove a file from the specified target, removing it from the entire project
#// if no other targets reference it.
#//
#//--------------------------------------------------------------------------------------------------
sub RemoveFileFromTarget($$$)
{
my($doc, $target_node, $file_name) = @_;
# the file must be removed in 3 places:
# 1. in <TARGET><FILELIST><FILE>
# 2. in <TARGET><LINKORDER><FILEREF>
# 3. in <GROUPLIST><GROUP><FILEREF>
# first, remove from <FILELIST>
my $filelist_node = getFirstChildElement($target_node, "FILELIST");
unless ($filelist_node) { die "Error: failed to find FILELIST node\n"; }
my $file_node = getChildNodeByGrandchildContents($doc, $filelist_node, "FILE", "PATH", $file_name);
unless ($file_node) { return; }
$filelist_node->removeChild($file_node);
# next, remove from <LINKORDER>
my $linkorder_node = getFirstChildElement($target_node, "LINKORDER");
unless ($linkorder_node) { die "Error: failed to find LINKORDER node\n"; }
my $fileref_node = getChildNodeByGrandchildContents($doc, $linkorder_node, "FILEREF", "PATH", $file_name);
unless ($fileref_node) { die "Error: link order node for file $file_name not found\n"; }
$linkorder_node->removeChild($fileref_node);
# last, remove from <GROUPLIST>
# <GROUPLIST> is cross-target, so we have to be careful here.
my $grouplist_node = getChildOfDocument($doc, "GROUPLIST");
unless ($grouplist_node) { die "Error: failed to find GROUPLIST node\n"; }
# if the file isn't in any other targets, remove it from the groups
if (!GetFileInUse($doc, $file_name))
{
print "File $file_name is in no other targest. Removing from project\n";
my @group_nodes;
getChildElementsOfType($doc, $grouplist_node, "GROUP", \@group_nodes);
my $group_node;
foreach $group_node (@group_nodes)
{
my @fileref_nodes;
getChildElementsOfType($doc, $group_node, "FILEREF", \@fileref_nodes);
my $fileref_node;
foreach $fileref_node (@fileref_nodes)
{
my $path_name = getChildElementTextContents($fileref_node, "PATH");
if ($path_name eq $file_name)
{
print "Removing $file_name from project group list\n";
$group_node->removeChild($fileref_node);
last;
}
}
# can a file appear in more than one group?
}
}
}
#//--------------------------------------------------------------------------------------------------
#// SetAsStaticLibraryTarget
#//
#//--------------------------------------------------------------------------------------------------
sub SetAsStaticLibraryTarget($$$)
{
my($doc, $target_name, $output_name) = @_;
my $target_node = getTargetNode($doc, $target_name);
setTargetNodeSetting($doc, $target_node, "MWProject_PPC_type", "Library");
setTargetNodeSetting($doc, $target_node, "MWProject_PPC_filetype", "1061109567"); #'????'
setTargetNodeSetting($doc, $target_node, "MWProject_PPC_outfile", $output_name);
# static targets don't need any library linkage, so we can remove linkage
# with all .shlb and .Lib files.
my(@obsolete_files) = ("NSStdLibStubs", "InterfacesStubs", "InterfaceLib", "InternetConfigLib");
print " Removing libraries etc. from target\n";
# get all files in target
my @target_files = GetTargetFilesList($doc, $target_name);
my $target_file;
foreach $target_file (@target_files)
{
if ($target_file =~ /(\.shlb|\.lib|\.Lib|\.o|\.exp)$/)
{
RemoveFileFromTarget($doc, $target_node, $target_file);
}
}
print " Removing stub libraries from target\n";
# then remove files with known names
my $obs_file;
foreach $obs_file (@obsolete_files)
{
RemoveFileFromTarget($doc, $target_node, $obs_file);
}
}
#//--------------------------------------------------------------------------------------------------
#// AddTarget
#//
#//--------------------------------------------------------------------------------------------------
sub AddTarget($$)
{
my($doc, $target_name) = @_;
die "Write me\n";
}
#//--------------------------------------------------------------------------------------------------
#// RemoveTarget
#//
#//--------------------------------------------------------------------------------------------------
sub RemoveTarget($$)
{
my($doc, $target_name) = @_;
die "Write me\n";
}
#//--------------------------------------------------------------------------------------------------
#// GetTargetSetting
#// Get the value for the specified setting in the specified target
#//--------------------------------------------------------------------------------------------------
sub GetTargetSetting($$$)
{
my($doc, $target_name, $setting_name) = @_;
my $target_node = getTargetNode($doc, $target_name);
return getTargetNodeSetting($target_node, "VALUE");
}
#//--------------------------------------------------------------------------------------------------
#// SetTargetSetting
#// Set the value for the specified setting in the specified target
#//--------------------------------------------------------------------------------------------------
sub SetTargetSetting($$$$)
{
my($doc, $target_name, $setting_name, $new_value) = @_;
my $target_node = getTargetNode($doc, $target_name);
setTargetNodeSetting($doc, $target_node, "VALUE", $new_value);
}
#//--------------------------------------------------------------------------------------------------
#// GetTargetFilesList
#// Return an array of the files in the target (in filelist order)
#//--------------------------------------------------------------------------------------------------
sub GetTargetFilesList($$)
{
my($doc, $target_name) = @_;
my $target_node = getTargetNode($doc, $target_name);
my @files_list;
my $filelist_node = getFirstChildElement($target_node, "FILELIST");
unless ($filelist_node) { die "Error: failed to find FILELIST node\n"; }
my @file_nodes;
getChildElementsOfType($doc, $filelist_node, "FILE", \@file_nodes);
my $node;
foreach $node (@file_nodes)
{
my $file_name = getChildElementTextContents($node, "PATH");
push(@files_list, $file_name);
}
return @files_list;
}
#//--------------------------------------------------------------------------------------------------
#// FileIsInTarget
#//
#//--------------------------------------------------------------------------------------------------
sub FileIsInTarget($$$)
{
my($doc, $file_name, $target_name) = @_;
my $target_node = getTargetNode($doc, $target_name);
unless ($target_node) { die "Error: no target found called $target_name\n"; }
my $file_node = GetTargetFileNode($doc, $target_node, $file_name);
if ($file_node) {
return 1;
}
return 0;
}
#//--------------------------------------------------------------------------------------------------
#// GetFileTargetsList
#// Return an array of the targets that a file is in (expensive)
#//--------------------------------------------------------------------------------------------------
sub GetFileTargetsList($$)
{
my ($doc, $file_name) = @_;
my @target_list;
my @targets = GetTargetsList($doc);
my $target;
foreach $target (@targets)
{
if (FileIsInTarget($doc, $file_name, $target))
{
push(@target_list, $target);
}
}
return @target_list;
}
#//--------------------------------------------------------------------------------------------------
#// GetTargetFileNode
#//
#//--------------------------------------------------------------------------------------------------
sub GetTargetFileNode($$$)
{
my($doc, $target_node, $file_name) = @_;
my $filelist_node = getFirstChildElement($target_node, "FILELIST");
unless ($filelist_node) { die "Error: failed to find FILELIST node\n"; }
my $file_node = getChildNodeByGrandchildContents($doc, $filelist_node, "FILE", "PATH", $file_name);
return $file_node;
}
#//--------------------------------------------------------------------------------------------------
#// GetFileInUse
#// Return true if the file is used by any target
#//--------------------------------------------------------------------------------------------------
sub GetFileInUse($$)
{
my($doc, $file_name) = @_;
my $targetlist_node = getChildOfDocument($doc, "TARGETLIST");
my $target_node = $targetlist_node->getFirstChild();
while ($target_node)
{
if ($target_node->getNodeTypeName eq "ELEMENT_NODE" &&
$target_node->getTagName() eq "TARGET")
{
# if this is a target node
my $file_node = GetTargetFileNode($doc, $target_node, $file_name);
if ($file_node) {
return 1; # found it
}
}
$target_node = $target_node->getNextSibling();
}
# not found
return 0;
}
#//--------------------------------------------------------------------------------------------------
#// getChildOfDocument
#//--------------------------------------------------------------------------------------------------
sub getChildOfDocument($$)
{
my($doc, $child_type) = @_;
return getFirstChildElement($doc->getDocumentElement(), $child_type);
}
#//--------------------------------------------------------------------------------------------------
#// getFirstChildElement
#//--------------------------------------------------------------------------------------------------
sub getFirstChildElement($$)
{
my($node, $element_name) = @_;
my $found_node;
unless ($node) { die "getFirstChildElement called with empty node\n"; }
#look for the first "element_name" child
my $child_node = $node->getFirstChild();
while ($child_node)
{
if ($child_node->getNodeTypeName eq "ELEMENT_NODE" &&
$child_node->getTagName() eq $element_name)
{
$found_node = $child_node;
last;
}
$child_node = $child_node->getNextSibling();
}
return $found_node;
}
#//--------------------------------------------------------------------------------------------------
#// getChildElementsOfType
#//
#// Return an array of refs to child nodes of the given type
#//--------------------------------------------------------------------------------------------------
sub getChildElementsOfType($$$$)
{
my($doc, $node, $child_type, $array_ref) = @_;
my $child_node = $node->getFirstChild();
while ($child_node)
{
if ($child_node->getNodeTypeName eq "ELEMENT_NODE" &&
$child_node->getTagName() eq $child_type)
{
push(@$array_ref, $child_node);
}
$child_node = $child_node->getNextSibling();
}
}
#//--------------------------------------------------------------------------------------------------
#// getChildElementTextContents
#//--------------------------------------------------------------------------------------------------
#
# Given <FOOPY><NERD>Hi!</NERD></FOOPY>, where $node is <FOOPY>,
# returns "Hi!". If > 1 <NERD> node, returns the contents of the first.
#
sub getChildElementTextContents($$)
{
my($node, $tag_name) = @_;
my $first_element = getFirstChildElement($node, $tag_name);
my $text_node = $first_element->getFirstChild();
my $text_contents = "";
# concat adjacent text nodes
while ($text_node)
{
if ($text_node->getNodeTypeName() ne "TEXT_NODE")
{
last;
}
$text_contents = $text_contents.$text_node->getData();
$text_node = $text_node->getNextSibling();
}
return $text_contents;
}
#//--------------------------------------------------------------------------------------------------
#// setChildElementTextContents
#//--------------------------------------------------------------------------------------------------
sub setChildElementTextContents($$$$)
{
my($doc, $node, $tag_name, $contents_text) = @_;
my $first_element = getFirstChildElement($node, $tag_name);
my $new_text_node = $doc->createTextNode($contents_text);
# replace all child elements with a text element
removeAllChildren($first_element);
$first_element->appendChild($new_text_node);
}
#//--------------------------------------------------------------------------------------------------
#// getChildNodeByContents
#//
#// Consider <foo><bar><baz>Foopy</baz></bar><bar><baz>Loopy</baz></bar></foo>
#// This function, when called with getChildNodeByContents($foonode, "bar", "baz", "Loopy")
#// returns the second <bar> node.
#//--------------------------------------------------------------------------------------------------
sub getChildNodeByGrandchildContents($$$$$)
{
my($doc, $node, $child_type, $gc_type, $gc_contents) = @_; # gc = grandchild
my $found_node;
my $child_node = $node->getFirstChild();
while ($child_node)
{
if ($child_node->getNodeTypeName eq "ELEMENT_NODE" &&
$child_node->getTagName() eq $child_type)
{
# check for a child of this node of type
my $child_contents = getChildElementTextContents($child_node, $gc_type);
if ($child_contents eq $gc_contents)
{
$found_node = $child_node;
last;
}
}
$child_node = $child_node->getNextSibling();
}
return $found_node;
}
#//--------------------------------------------------------------------------------------------------
#// getTargetNode
#//--------------------------------------------------------------------------------------------------
sub getTargetNode($$)
{
my($doc, $target_name) = @_;
my $targetlist_node = getChildOfDocument($doc, "TARGETLIST");
return getChildNodeByGrandchildContents($doc, $targetlist_node, "TARGET", "NAME", $target_name);
}
#//--------------------------------------------------------------------------------------------------
#// getTargetNamedSettingNode
#//--------------------------------------------------------------------------------------------------
sub getTargetNamedSettingNode($$)
{
my($target_node, $setting_name) = @_;
my $setting_node;
my $settinglist_node = getFirstChildElement($target_node, "SETTINGLIST");
my $child_node = $settinglist_node->getFirstChild();
while ($child_node)
{
if ($child_node->getNodeTypeName ne "ELEMENT_NODE")
{
$child_node = $child_node->getNextSibling();
next;
}
if ($child_node->getTagName() eq "SETTING")
{
my $set_name = getChildElementTextContents($child_node, "NAME");
if ($set_name eq $setting_name)
{
$setting_node = $child_node;
last;
}
}
$child_node = $child_node->getNextSibling();
}
return $setting_node;
}
#//--------------------------------------------------------------------------------------------------
#// getTargetNodeSetting
#//--------------------------------------------------------------------------------------------------
sub getTargetNodeSetting($$)
{
my($target_node, $setting_name) = @_;
my $setting_node = getTargetNamedSettingNode($target_node, $setting_name);
return getChildElementTextContents($setting_node, "VALUE");
}
#//--------------------------------------------------------------------------------------------------
#// setTargetNodeSetting
#//--------------------------------------------------------------------------------------------------
sub setTargetNodeSetting($$$$)
{
my($doc, $target_node, $setting_name, $new_value) = @_;
my $setting_node = getTargetNamedSettingNode($target_node, $setting_name);
setChildElementTextContents($doc, $setting_node, "VALUE", $new_value);
}
#//--------------------------------------------------------------------------------------------------
#// elementInArray
#//--------------------------------------------------------------------------------------------------
sub elementInArray($$)
{
my($element, $array) = @_;
my $test;
foreach $test (@$array)
{
if ($test eq $element) {
return 1;
}
}
return 0;
}
#//--------------------------------------------------------------------------------------------------
#// removeAllChildren
#//--------------------------------------------------------------------------------------------------
sub removeAllChildren($)
{
my($node) = @_;
my $child_node = $node->getFirstChild();
while ($child_node)
{
$node->removeChild($child_node);
$child_node = $node->getFirstChild();
}
}
#//--------------------------------------------------------------------------------------------------
#// dumpNodeData
#//--------------------------------------------------------------------------------------------------
sub dumpNodeData($)
{
my($node) = @_;
unless ($node) { die "Null node passed to dumpNodeData\n"; }
print "Dumping node $node\n";
my($node_type) = $node->getNodeTypeName();
if ($node_type eq "ELEMENT_NODE")
{
my($node_name) = $node->getTagName();
print "Element $node_name\n";
}
elsif ($node_type eq "TEXT_NODE")
{
my($node_data) = $node->getData;
# my(@node_vals) = unpack("C*", $node_data);
print "Text '$node_data'\n"; # may contain LF chars
}
else
{
print "Node $node_type\n";
}
}
#//--------------------------------------------------------------------------------------------------
#// dumpNodeTree
#//--------------------------------------------------------------------------------------------------
sub dumpNodeTree($)
{
my($node) = @_;
my($child_node) = $node->getFirstChild();
unless ($child_node) { return; }
# recurse
dumpNodeData($child_node);
# then go through child nodes
while ($child_node)
{
dumpNodeTree($child_node);
$child_node = $child_node->getNextSibling();
}
}
1;

View File

@@ -1,90 +0,0 @@
#-------------------------------------------------------------------------------
# These 3 lists are the 'master lists' to control what gets built.
#
# Ordering in these arrays is important; it has to reflect the order in
# which the build occurs.
#
# Setting containing spaces must be quoted with double quotes.
#-------------------------------------------------------------------------------
build_flags
all 1
pull 0
dist 0
config 0
xpidl 0
idl 0
stubs 0
runtime 0
common 0
imglib 0
libimg2 0
necko 0
security 0
browserutils 0
intl 0
nglayout 0
accessiblity 0
editor 0
embedding 0
viewer 0
xpapp 0
extensions 0
plugins 0
mailnews 0
apprunner 0
resources 0
options_flags
pull_by_date 0
chrome_jars 1
chrome_files 0
use_jars 1
transformiix 1
mathml 0 MOZ_MATHML
svg 0 MOZ_SVG
# svg requires libart, which is an lgpl library. You need to pull it
# explicitly.
libart_lgpl 0
mng 1
ldap 1 MOZ_LDAP_XPCOM
ldap_experimental 0 MOZ_LDAP_XPCOM_EXPERIMENTAL
xmlextras 1
wsp 0 MOZ_WSP
inspector 1
mailextras 1
xptlink 0
psm 0 MOZ_PSM
embedding_test 1
embedding_chrome 0
embedding_xulprefs 0
embedding_xulsecurity 0
carbon 0 TARGET_CARBON
useimg2 1 USE_IMG2
lowmem 0 MOZ_MAC_LOWMEM
accessible 1 ACCESSIBILITY
bidi 1 IBMBIDI
p3p 0
jsd 1
venkman 1
moz_logging 1 MOZ_LOGGING
chatzilla 1
content_packs 1
xml_rpc 1
cview 1
help 1
timeline 0 MOZ_TIMELINE
static_build 0 MOZ_STATIC_COMPONENT_LIBS
string_debug 0 DEBUG_STRING
string_stats 0 DEBUG_STRING_STATS
xpctools 0 XPC_TOOLS_SUPPORT
smime 1
mdn 1
print_preview 1 NS_PRINT_PREVIEW
moz_xul 1 MOZ_XUL
filepath_flags
idepath ":CodeWarrior IDE Path.txt"
sessionpath ":Mozilla session path.txt"
buildlogfilepath ":Build Logs:Mozilla build log.txt" # this is a path
scriptlogfilepath ":Build Logs:Mozilla script log.txt"

File diff suppressed because it is too large Load Diff

View File

@@ -1,22 +0,0 @@
# List of modules to check out. Format is
# module, (tag), (date)
# where tag and date are optional (non-trailing commas are required)
#
# Examples:
# mozilla/nsprpub, NSPRPUB_CLIENT_TAG
# mozilla/gc, , 10/25/2000 12:00:00
#
mozilla/nsprpub, NETSCAPE_7_02_RELEASE
mozilla/security/nss, NETSCAPE_7_02_RELEASE
mozilla/security/manager, NETSCAPE_7_02_RELEASE
mozilla/accessible, NETSCAPE_7_02_RELEASE
mozilla/directory/c-sdk, NETSCAPE_7_02_RELEASE
mozilla/lib/mac/Instrumentation, NETSCAPE_7_02_RELEASE
mozilla/gfx2, NETSCAPE_7_02_RELEASE
mozilla/modules/libpr0n, NETSCAPE_7_02_RELEASE
SeaMonkeyAll, NETSCAPE_7_02_RELEASE
## You need this if you want to be able to use SVG
## Note that this library is under the LGPL, not the MPL
#mozilla/other-licenses/libart_lgpl

View File

@@ -1,79 +0,0 @@
#!perl
#
# 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) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
# Simon Fraser <sfraser@netscape.com>
#
require 5.004;
use strict;
use Cwd;
use Moz::BuildUtils;
use Moz::BuildCore;
#-------------------------------------------------------------
# Where have the build options gone?
#
# The various build flags have been centralized into one place.
# The master list of options is in MozBuildFlags.txt. However,
# you should never need to edit that file, or this one.
#
# To customize what gets built, or where to start the build,
# edit the $prefs_file_name file in
# System Folder:Preferences:Mozilla build prefs:
# Documentation is provided in that file.
#-------------------------------------------------------------
my($prefs_file_name) = "Mozilla pull prefs";
#-------------------------------------------------------------
# hashes to hold build options
#-------------------------------------------------------------
my(%build);
my(%options);
my(%filepaths);
my(%optiondefines);
# Hash of input files for this build. Eventually, there will be
# input files for manifests, and projects too.
my(%inputfiles) = (
"buildflags", "MozillaBuildFlags.txt",
"checkoutdata", "MozillaCheckoutList.txt",
"buildprogress", "",
"buildmodule", "MozillaBuildList.pm",
"checkouttime", "Mozilla last checkout"
);
#-------------------------------------------------------------
# end build hashes
#-------------------------------------------------------------
# set the build root directory, which is the the dir above mozilla
SetupBuildRootDir(":mozilla:build:mac:build_scripts");
# Set up all the flags on $main::, like DEBUG, CARBON etc.
# Override the defaults using the preferences files.
SetupDefaultBuildOptions(0, ":mozilla:dist:viewer:", "");
my($do_checkout) = 1;
my($do_build) = 0;
RunBuild($do_checkout, $do_build, \%inputfiles, $prefs_file_name);

View File

@@ -1,4 +0,0 @@
This directory is merely here to test the project editor server. It will go away after
it is validated. For more information, see http://camelot.
Testing watchers.

Binary file not shown.

Binary file not shown.

View File

@@ -1 +0,0 @@
// test1.cpp

View File

@@ -1 +0,0 @@
// test2.cpp

Binary file not shown.

View File

@@ -1 +0,0 @@
// test2.cpp

Binary file not shown.

Binary file not shown.

View File

@@ -1,4 +0,0 @@
// test2.cpp
as
dfasdf

View File

@@ -1,12 +0,0 @@
#include <stdio.h>
#include <ConditionalMacros.h>
int main(int argc, char* argv[])
{
FILE* file = fopen("BuildSystemInfo.pm", "w");
if (file != NULL) {
fprintf(file, "$UNIVERSAL_INTERFACES_VERSION=0x%04X;\n", UNIVERSAL_INTERFACES_VERSION);
fclose(file);
}
}

View File

@@ -1,650 +0,0 @@
# 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) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Stephen Lamm
# Build the Mozilla client.
#
# This needs CVSROOT set to work, e.g.,
# setenv CVSROOT :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot
# or
# setenv CVSROOT :pserver:username%somedomain.org@cvs.mozilla.org:/cvsroot
#
# To checkout and build a tree,
# 1. cvs co mozilla/client.mk
# 2. cd mozilla
# 3. gmake -f client.mk
#
# Other targets (gmake -f client.mk [targets...]),
# checkout
# build
# clean (realclean is now the same as clean)
# distclean
#
# See http://www.mozilla.org/build/unix.html for more information.
#
# Options:
# MOZ_OBJDIR - Destination object directory
# MOZ_CO_DATE - Date tag to use for checkout (default: none)
# MOZ_CO_MODULE - Module to checkout (default: SeaMonkeyAll)
# MOZ_CVS_FLAGS - Flags to pass cvs (default: -q -z3)
# MOZ_CO_FLAGS - Flags to pass after 'cvs co' (default: -P)
# MOZ_MAKE_FLAGS - Flags to pass to $(MAKE)
# MOZ_CO_BRANCH - Branch tag (Deprecated. Use MOZ_CO_TAG below.)
#
#######################################################################
# Checkout Tags
#
# For branches, uncomment the MOZ_CO_TAG line with the proper tag,
# and commit this file on that tag.
MOZ_CO_TAG = NETSCAPE_7_02_RELEASE
NSPR_CO_TAG = NETSCAPE_7_02_RELEASE
PSM_CO_TAG = NETSCAPE_7_02_RELEASE
NSS_CO_TAG = NETSCAPE_7_02_RELEASE
LDAPCSDK_CO_TAG = NETSCAPE_7_02_RELEASE
ACCESSIBLE_CO_TAG = NETSCAPE_7_02_RELEASE
GFX2_CO_TAG = NETSCAPE_7_02_RELEASE
IMGLIB2_CO_TAG = NETSCAPE_7_02_RELEASE
BUILD_MODULES = all
#######################################################################
# Defines
#
CVS = cvs
CWD := $(shell pwd)
ifeq "$(CWD)" "/"
CWD := /.
endif
ifneq (, $(wildcard client.mk))
# Ran from mozilla directory
ROOTDIR := $(shell dirname $(CWD))
TOPSRCDIR := $(CWD)
else
# Ran from mozilla/.. directory (?)
ROOTDIR := $(CWD)
TOPSRCDIR := $(CWD)/mozilla
endif
# on os2, TOPSRCDIR may have two forward slashes in a row, which doesn't
# work; replace first instance with one forward slash
TOPSRCDIR := $(shell echo "$(TOPSRCDIR)" | sed -e 's%//%/%')
ifndef TOPSRCDIR_MOZ
TOPSRCDIR_MOZ=$(TOPSRCDIR)
endif
# if ROOTDIR equals only drive letter (i.e. "C:"), set to "/"
DIRNAME := $(shell echo "$(ROOTDIR)" | sed -e 's/^.://')
ifeq ($(DIRNAME),)
ROOTDIR := /.
endif
AUTOCONF := autoconf
MKDIR := mkdir
SH := /bin/sh
ifndef MAKE
MAKE := gmake
endif
CONFIG_GUESS_SCRIPT := $(wildcard $(TOPSRCDIR)/build/autoconf/config.guess)
ifdef CONFIG_GUESS_SCRIPT
CONFIG_GUESS = $(shell $(CONFIG_GUESS_SCRIPT))
else
_IS_FIRST_CHECKOUT := 1
endif
####################################
# CVS
# Add the CVS root to CVS_FLAGS if needed
CVS_ROOT_IN_TREE := $(shell cat $(TOPSRCDIR)/CVS/Root 2>/dev/null)
ifneq ($(CVS_ROOT_IN_TREE),)
ifneq ($(CVS_ROOT_IN_TREE),$(CVSROOT))
CVS_FLAGS := -d $(CVS_ROOT_IN_TREE)
endif
endif
CVSCO = $(strip $(CVS) $(CVS_FLAGS) co $(CVS_CO_FLAGS))
CVSCO_LOGFILE := $(ROOTDIR)/cvsco.log
CVSCO_LOGFILE := $(shell echo $(CVSCO_LOGFILE) | sed s%//%/%)
ifdef MOZ_CO_TAG
CVS_CO_FLAGS := -r $(MOZ_CO_TAG)
endif
####################################
# Load mozconfig Options
# See build pages, http://www.mozilla.org/build/unix.html,
# for how to set up mozconfig.
MOZCONFIG_LOADER := mozilla/build/autoconf/mozconfig2client-mk
MOZCONFIG_FINDER := mozilla/build/autoconf/mozconfig-find
MOZCONFIG_MODULES := mozilla/build/unix/modules.mk
run_for_side_effects := \
$(shell cd $(ROOTDIR); \
if test "$(_IS_FIRST_CHECKOUT)"; then \
$(CVSCO) $(MOZCONFIG_FINDER) $(MOZCONFIG_LOADER) $(MOZCONFIG_MODULES); \
else true; \
fi; \
$(MOZCONFIG_LOADER) $(TOPSRCDIR) mozilla/.mozconfig.mk > mozilla/.mozconfig.out)
include $(TOPSRCDIR)/.mozconfig.mk
include $(TOPSRCDIR)/build/unix/modules.mk
####################################
# Options that may come from mozconfig
# Change CVS flags if anonymous root is requested
ifdef MOZ_CO_USE_MIRROR
CVS_FLAGS := -d :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot
endif
# MOZ_CVS_FLAGS - Basic CVS flags
ifeq "$(origin MOZ_CVS_FLAGS)" "undefined"
CVS_FLAGS := $(CVS_FLAGS) -q -z 3
else
CVS_FLAGS := $(MOZ_CVS_FLAGS)
endif
# This option is deprecated. The best way to have client.mk pull a tag
# is to set MOZ_CO_TAG (see above) and commit that change on the tag.
ifdef MOZ_CO_BRANCH
$(warning Use MOZ_CO_TAG instead of MOZ_CO_BRANCH)
CVS_CO_FLAGS := -r $(MOZ_CO_BRANCH)
endif
# MOZ_CO_FLAGS - Anything that we should use on all checkouts
ifeq "$(origin MOZ_CO_FLAGS)" "undefined"
CVS_CO_FLAGS := $(CVS_CO_FLAGS) -P
else
CVS_CO_FLAGS := $(CVS_CO_FLAGS) $(MOZ_CO_FLAGS)
endif
ifdef MOZ_CO_DATE
CVS_CO_DATE_FLAGS := -D "$(MOZ_CO_DATE)"
endif
ifdef MOZ_OBJDIR
OBJDIR := $(MOZ_OBJDIR)
MOZ_MAKE := $(MAKE) $(MOZ_MAKE_FLAGS) -C $(OBJDIR)
else
OBJDIR := $(TOPSRCDIR)
MOZ_MAKE := $(MAKE) $(MOZ_MAKE_FLAGS)
endif
####################################
# CVS defines for PSM
#
PSM_CO_MODULE= mozilla/security/manager
PSM_CO_FLAGS := -P -A
ifdef MOZ_CO_FLAGS
PSM_CO_FLAGS := $(MOZ_CO_FLAGS)
endif
ifdef PSM_CO_TAG
PSM_CO_FLAGS := $(PSM_CO_FLAGS) -r $(PSM_CO_TAG)
endif
CVSCO_PSM = $(CVS) $(CVS_FLAGS) co $(PSM_CO_FLAGS) $(CVS_CO_DATE_FLAGS) $(PSM_CO_MODULE)
####################################
# CVS defines for NSS
#
NSS_CO_MODULE = mozilla/security/nss \
mozilla/security/coreconf \
$(NULL)
NSS_CO_FLAGS := -P
ifdef MOZ_CO_FLAGS
NSS_CO_FLAGS := $(MOZ_CO_FLAGS)
endif
ifdef NSS_CO_TAG
NSS_CO_FLAGS := $(NSS_CO_FLAGS) -r $(NSS_CO_TAG)
endif
# Cannot pull static tags by date
ifeq ($(NSS_CO_TAG),NSS_CLIENT_TAG)
CVSCO_NSS = $(CVS) $(CVS_FLAGS) co $(NSS_CO_FLAGS) $(NSS_CO_MODULE)
else
CVSCO_NSS = $(CVS) $(CVS_FLAGS) co $(NSS_CO_FLAGS) $(CVS_CO_DATE_FLAGS) $(NSS_CO_MODULE)
endif
####################################
# CVS defines for NSPR
#
NSPR_CO_MODULE = mozilla/nsprpub
NSPR_CO_FLAGS := -P
ifdef MOZ_CO_FLAGS
NSPR_CO_FLAGS := $(MOZ_CO_FLAGS)
endif
ifdef NSPR_CO_TAG
NSPR_CO_FLAGS := $(NSPR_CO_FLAGS) -r $(NSPR_CO_TAG)
endif
# Cannot pull static tags by date
ifeq ($(NSPR_CO_TAG),NSPRPUB_CLIENT_TAG)
CVSCO_NSPR = $(CVS) $(CVS_FLAGS) co $(NSPR_CO_FLAGS) $(NSPR_CO_MODULE)
else
CVSCO_NSPR = $(CVS) $(CVS_FLAGS) co $(NSPR_CO_FLAGS) $(CVS_CO_DATE_FLAGS) $(NSPR_CO_MODULE)
endif
####################################
# CVS defines for the C LDAP SDK
#
LDAPCSDK_CO_MODULE = mozilla/directory/c-sdk
LDAPCSDK_CO_FLAGS := -P
ifdef MOZ_CO_FLAGS
LDAPCSDK_CO_FLAGS := $(MOZ_CO_FLAGS)
endif
ifdef LDAPCSDK_CO_TAG
LDAPCSDK_CO_FLAGS := $(LDAPCSDK_CO_FLAGS) -r $(LDAPCSDK_CO_TAG)
endif
CVSCO_LDAPCSDK = $(CVS) $(CVS_FLAGS) co $(LDAPCSDK_CO_FLAGS) $(CVS_CO_DATE_FLAGS) $(LDAPCSDK_CO_MODULE)
####################################
# CVS defines for the C LDAP SDK
#
ACCESSIBLE_CO_MODULE = mozilla/accessible
ACCESSIBLE_CO_FLAGS := -P
ifdef MOZ_CO_FLAGS
ACCESSIBLE_CO_FLAGS := $(MOZ_CO_FLAGS)
endif
ifdef ACCESSIBLE_CO_TAG
ACCESSIBLE_CO_FLAGS := $(ACCESSIBLE_CO_FLAGS) -r $(ACCESSIBLE_CO_TAG)
endif
CVSCO_ACCESSIBLE = $(CVS) $(CVS_FLAGS) co $(ACCESSIBLE_CO_FLAGS) $(CVS_CO_DATE_FLAGS) $(ACCESSIBLE_CO_MODULE)
####################################
# CVS defines for gfx2
#
GFX2_CO_MODULE = mozilla/gfx2
GFX2_CO_FLAGS := -P
ifdef MOZ_CO_FLAGS
GFX2_CO_FLAGS := $(MOZ_CO_FLAGS)
endif
ifdef GFX2_CO_TAG
GFX2_CO_FLAGS := $(GFX2_CO_FLAGS) -r $(GFX2_CO_TAG)
endif
CVSCO_GFX2 = $(CVS) $(CVS_FLAGS) co $(GFX2_CO_FLAGS) $(CVS_CO_DATE_FLAGS) $(GFX2_CO_MODULE)
####################################
# CVS defines for new image library
#
IMGLIB2_CO_MODULE = mozilla/modules/libpr0n
IMGLIB2_CO_FLAGS := -P
ifdef MOZ_CO_FLAGS
IMGLIB2_CO_FLAGS := $(MOZ_CO_FLAGS)
endif
ifdef IMGLIB2_CO_TAG
IMGLIB2_CO_FLAGS := $(IMGLIB2_CO_FLAGS) -r $(IMGLIB2_CO_TAG)
endif
CVSCO_IMGLIB2 = $(CVS) $(CVS_FLAGS) co $(IMGLIB2_CO_FLAGS) $(CVS_CO_DATE_FLAGS) $(IMGLIB2_CO_MODULE)
####################################
# CVS defines for standalone modules
#
ifneq ($(BUILD_MODULES),all)
MOZ_CO_MODULE := $(filter-out $(NSPRPUB_DIR) security directory/c-sdk, $(BUILD_MODULE_CVS))
MOZ_CO_MODULE += allmakefiles.sh client.mk aclocal.m4 configure configure.in
MOZ_CO_MODULE += Makefile.in
MOZ_CO_MODULE := $(addprefix mozilla/, $(MOZ_CO_MODULE))
NOSUBDIRS_MODULE := $(addprefix mozilla/, $(BUILD_MODULE_CVS_NS))
ifneq ($(NOSUBDIRS_MODULE),)
CVSCO_NOSUBDIRS := $(CVSCO) -l $(CVS_CO_DATE_FLAGS) $(NOSUBDIRS_MODULE)
endif
ifeq (,$(filter $(NSPRPUB_DIR), $(BUILD_MODULE_CVS)))
CVSCO_NSPR :=
endif
ifeq (,$(filter security security/manager, $(BUILD_MODULE_CVS)))
CVSCO_PSM :=
CVSCO_NSS :=
endif
ifeq (,$(filter directory/c-sdk, $(BUILD_MODULE_CVS)))
CVSCO_LDAPCSDK :=
endif
ifeq (,$(filter accessible, $(BUILD_MODULE_CVS)))
CVSCO_ACCESSIBLE :=
endif
ifeq (,$(filter gfx2, $(BUILD_MODULE_CVS)))
CVSCO_GFX2 :=
endif
ifeq (,$(filter modules/libpr0n, $(BUILD_MODULE_CVS)))
CVSCO_IMGLIB2 :=
endif
endif
####################################
# CVS defines for SeaMonkey
#
ifeq ($(MOZ_CO_MODULE),)
MOZ_CO_MODULE := SeaMonkeyAll
endif
CVSCO_SEAMONKEY := $(CVSCO) $(CVS_CO_DATE_FLAGS) $(MOZ_CO_MODULE)
####################################
# CVS defined for libart (pulled and built if MOZ_INTERNAL_LIBART_LGPL is set)
#
CVSCO_LIBART := $(CVSCO) $(CVS_CO_DATE_FLAGS) mozilla/other-licenses/libart_lgpl
ifdef MOZ_INTERNAL_LIBART_LGPL
FASTUPDATE_LIBART := fast_update $(CVSCO_LIBART)
CHECKOUT_LIBART := cvs_co $(CVSCO_LIBART)
else
CHECKOUT_LIBART := true
FASTUPDATE_LIBART := true
endif
####################################
# CVS defines for Calendar (pulled and built if MOZ_CALENDAR is set)
#
CVSCO_CALENDAR := $(CVSCO) $(CVS_CO_DATE_FLAGS) mozilla/calendar
ifdef MOZ_CALENDAR
FASTUPDATE_CALENDAR := fast_update $(CVSCO_CALENDAR)
CHECKOUT_CALENDAR := cvs_co $(CVSCO_CALENDAR)
else
CHECKOUT_CALENDAR := true
FASTUPDATE_CALENDAR := true
endif
# because some cygwin tools can't handle native dos-drive paths & vice-versa
# force configure to use a relative path for --srcdir
# need a better check for win32
# and we need to get OBJDIR earlier
ifdef MOZ_TOOLS
_tmpobjdir := $(shell cygpath -u $(OBJDIR))
_abs2rel := $(shell cygpath -w $(TOPSRCDIR)/build/unix/abs2rel.pl | sed -e 's|\\|/|g')
_OBJ2SRCPATH := $(shell $(_abs2rel) $(TOPSRCDIR) $(_tmpobjdir))
endif
#######################################################################
# Rules
#
# Print out any options loaded from mozconfig.
all build checkout clean depend distclean export libs install realclean::
@if test -f .mozconfig.out; then \
cat .mozconfig.out; \
rm -f .mozconfig.out; \
else true; \
fi
ifdef _IS_FIRST_CHECKOUT
all:: checkout build
else
all:: checkout alldep
endif
# Windows equivalents
pull_all: checkout
build_all: build
build_all_dep: alldep
build_all_depend: alldep
clobber clobber_all: clean
pull_and_build_all: checkout alldep
# Do everything from scratch
everything: checkout clean build
####################################
# CVS checkout
#
checkout::
# @: Backup the last checkout log.
@if test -f $(CVSCO_LOGFILE) ; then \
mv $(CVSCO_LOGFILE) $(CVSCO_LOGFILE).old; \
else true; \
fi
ifdef RUN_AUTOCONF_LOCALLY
@echo "Removing local configures" ; \
cd $(ROOTDIR) && \
$(RM) -f mozilla/configure mozilla/nsprpub/configure \
mozilla/directory/c-sdk/configure
endif
@echo "checkout start: "`date` | tee $(CVSCO_LOGFILE)
@echo '$(CVSCO) mozilla/client.mk mozilla/build/unix/modules.mk'; \
cd $(ROOTDIR) && \
$(CVSCO) mozilla/client.mk mozilla/build/unix/modules.mk
@cd $(ROOTDIR) && $(MAKE) -f mozilla/client.mk real_checkout
real_checkout:
# @: Start the checkout. Split the output to the tty and a log file. \
# : If it fails, touch an error file because "tee" hides the error.
@failed=.cvs-failed.tmp; rm -f $$failed*; \
cvs_co() { echo "$$@" ; \
("$$@" || touch $$failed) 2>&1 | tee -a $(CVSCO_LOGFILE) && \
if test -f $$failed; then false; else true; fi; }; \
cvs_co $(CVSCO_NSPR) && \
cvs_co $(CVSCO_NSS) && \
cvs_co $(CVSCO_PSM) && \
cvs_co $(CVSCO_LDAPCSDK) && \
cvs_co $(CVSCO_ACCESSIBLE) && \
cvs_co $(CVSCO_GFX2) && \
cvs_co $(CVSCO_IMGLIB2) && \
$(CHECKOUT_CALENDAR) && \
$(CHECKOUT_LIBART) && \
cvs_co $(CVSCO_SEAMONKEY) && \
cvs_co $(CVSCO_NOSUBDIRS)
@echo "checkout finish: "`date` | tee -a $(CVSCO_LOGFILE)
# @: Check the log for conflicts. ;
@conflicts=`egrep "^C " $(CVSCO_LOGFILE)` ;\
if test "$$conflicts" ; then \
echo "$(MAKE): *** Conflicts during checkout." ;\
echo "$$conflicts" ;\
echo "$(MAKE): Refer to $(CVSCO_LOGFILE) for full log." ;\
false; \
else true; \
fi
ifdef RUN_AUTOCONF_LOCALLY
@echo Generating configures using $(AUTOCONF) ; \
cd $(TOPSRCDIR) && $(AUTOCONF) && \
cd $(TOPSRCDIR)/nsprpub && $(AUTOCONF) && \
cd $(TOPSRCDIR)/directory/c-sdk && $(AUTOCONF)
endif
fast-update:
# @: Backup the last checkout log.
@if test -f $(CVSCO_LOGFILE) ; then \
mv $(CVSCO_LOGFILE) $(CVSCO_LOGFILE).old; \
else true; \
fi
ifdef RUN_AUTOCONF_LOCALLY
@echo "Removing local configures" ; \
cd $(ROOTDIR) && \
$(RM) -f mozilla/configure mozilla/nsprpub/configure \
mozilla/directory/c-sdk/configure
endif
@echo "checkout start: "`date` | tee $(CVSCO_LOGFILE)
@echo '$(CVSCO) mozilla/client.mk mozilla/build/unix/modules.mk'; \
cd $(ROOTDIR) && \
$(CVSCO) mozilla/client.mk mozilla/build/unix/modules.mk
@cd $(TOPSRCDIR) && \
$(MAKE) -f client.mk real_fast-update
real_fast-update:
# @: Start the update. Split the output to the tty and a log file. \
# : If it fails, touch an error file because "tee" hides the error.
@failed=.fast_update-failed.tmp; rm -f $$failed*; \
fast_update() { (config/cvsco-fast-update.pl $$@ || touch $$failed) 2>&1 | tee -a $(CVSCO_LOGFILE) && \
if test -f $$failed; then false; else true; fi; }; \
cvs_co() { echo "$$@" ; \
("$$@" || touch $$failed) 2>&1 | tee -a $(CVSCO_LOGFILE) && \
if test -f $$failed; then false; else true; fi; }; \
fast_update $(CVSCO_NSPR) && \
cd $(ROOTDIR) && \
failed=mozilla/.fast_update-failed.tmp && \
cvs_co $(CVSCO_NSS) && \
failed=.fast_update-failed.tmp && \
cd mozilla && \
fast_update $(CVSCO_PSM) && \
fast_update $(CVSCO_LDAPCSDK) && \
fast_update $(CVSCO_ACCESSIBLE) && \
fast_update $(CVSCO_GFX2) && \
fast_update $(CVSCO_IMGLIB2) && \
$(FASTUPDATE_CALENDAR) && \
$(FASTUPDATE_LIBART) && \
fast_update $(CVSCO_SEAMONKEY) && \
fast_update $(CVSCO_NOSUBDIRS)
@echo "fast_update finish: "`date` | tee -a $(CVSCO_LOGFILE)
# @: Check the log for conflicts. ;
@conflicts=`egrep "^C " $(CVSCO_LOGFILE)` ;\
if test "$$conflicts" ; then \
echo "$(MAKE): *** Conflicts during fast-update." ;\
echo "$$conflicts" ;\
echo "$(MAKE): Refer to $(CVSCO_LOGFILE) for full log." ;\
false; \
else true; \
fi
ifdef RUN_AUTOCONF_LOCALLY
@echo Generating configures using $(AUTOCONF) ; \
cd $(TOPSRCDIR) && $(AUTOCONF) && \
cd $(TOPSRCDIR)/nsprpub && $(AUTOCONF) && \
cd $(TOPSRCDIR)/directory/c-sdk && $(AUTOCONF)
endif
####################################
# Web configure
WEBCONFIG_FILE := $(HOME)/.mozconfig
MOZCONFIG2CONFIGURATOR := build/autoconf/mozconfig2configurator
webconfig:
@cd $(TOPSRCDIR); \
url=`$(MOZCONFIG2CONFIGURATOR) $(TOPSRCDIR)`; \
echo Running mozilla with the following url: ;\
echo ;\
echo $$url ;\
mozilla -remote "openURL($$url)" || \
netscape -remote "openURL($$url)" || \
mozilla $$url || \
netscape $$url ;\
echo ;\
echo 1. Fill out the form on the browser. ;\
echo 2. Save the results to $(WEBCONFIG_FILE)
#####################################################
# First Checkout
ifdef _IS_FIRST_CHECKOUT
# First time, do build target in a new process to pick up new files.
build::
$(MAKE) -f $(TOPSRCDIR)/client.mk build
else
#####################################################
# After First Checkout
####################################
# Configure
CONFIG_STATUS := $(wildcard $(OBJDIR)/config.status)
CONFIG_CACHE := $(wildcard $(OBJDIR)/config.cache)
ifdef RUN_AUTOCONF_LOCALLY
EXTRA_CONFIG_DEPS := \
$(TOPSRCDIR)/aclocal.m4 \
$(wildcard $(TOPSRCDIR)/build/autoconf/*.m4) \
$(NULL)
$(TOPSRCDIR)/configure: $(TOPSRCDIR)/configure.in $(EXTRA_CONFIG_DEPS)
@echo Generating $@ using autoconf
cd $(TOPSRCDIR); $(AUTOCONF)
endif
CONFIG_STATUS_DEPS_L10N := $(wildcard $(TOPSRCDIR)/l10n/makefiles.all)
CONFIG_STATUS_DEPS := \
$(TOPSRCDIR)/configure \
$(TOPSRCDIR)/allmakefiles.sh \
$(TOPSRCDIR)/.mozconfig.mk \
$(wildcard $(TOPSRCDIR)/nsprpub/configure) \
$(wildcard $(TOPSRCDIR)/directory/c-sdk/configure) \
$(wildcard $(TOPSRCDIR)/mailnews/makefiles) \
$(CONFIG_STATUS_DEPS_L10N) \
$(wildcard $(TOPSRCDIR)/themes/makefiles) \
$(NULL)
# configure uses the program name to determine @srcdir@. Calling it without
# $(TOPSRCDIR) will set @srcdir@ to "."; otherwise, it is set to the full
# path of $(TOPSRCDIR).
ifeq ($(TOPSRCDIR),$(OBJDIR))
CONFIGURE := ./configure
else
CONFIGURE := $(TOPSRCDIR)/configure
endif
ifdef _OBJ2SRCPATH
CONFIGURE_ARGS := --srcdir=$(_OBJ2SRCPATH) $(CONFIGURE_ARGS)
endif
$(OBJDIR)/Makefile $(OBJDIR)/config.status: $(CONFIG_STATUS_DEPS)
@if test ! -d $(OBJDIR); then $(MKDIR) $(OBJDIR); else true; fi
@echo cd $(OBJDIR);
@echo $(CONFIGURE) $(CONFIGURE_ARGS)
@cd $(OBJDIR) && $(CONFIGURE_ENV_ARGS) $(CONFIGURE) $(CONFIGURE_ARGS) \
|| ( echo "*** Fix above errors and then restart with\
\"$(MAKE) -f client.mk build\"" && exit 1 )
@touch $(OBJDIR)/Makefile
ifdef CONFIG_STATUS
$(OBJDIR)/config/autoconf.mk: $(TOPSRCDIR)/config/autoconf.mk.in
cd $(OBJDIR); \
CONFIG_FILES=config/autoconf.mk ./config.status
endif
####################################
# Depend
depend:: $(OBJDIR)/Makefile $(OBJDIR)/config.status
$(MOZ_MAKE) export && $(MOZ_MAKE) depend
####################################
# Build it
build:: $(OBJDIR)/Makefile $(OBJDIR)/config.status
$(MOZ_MAKE)
####################################
# Other targets
# Pass these target onto the real build system
install export libs clean realclean distclean alldep:: $(OBJDIR)/Makefile $(OBJDIR)/config.status
$(MOZ_MAKE) $@
cleansrcdir:
@cd $(TOPSRCDIR); \
if [ -f webshell/embed/gtk/Makefile ]; then \
$(MAKE) -C webshell/embed/gtk distclean; \
fi; \
if [ -f Makefile ]; then \
$(MAKE) distclean ; \
else \
echo "Removing object files from srcdir..."; \
rm -fr `find . -type d \( -name .deps -print -o -name CVS \
-o -exec test ! -d {}/CVS \; \) -prune \
-o \( -name '*.[ao]' -o -name '*.so' \) -type f -print`; \
build/autoconf/clean-config.sh; \
fi;
# (! IS_FIRST_CHECKOUT)
endif
.PHONY: checkout real_checkout depend build export libs alldep install clean realclean distclean cleansrcdir pull_all build_all clobber clobber_all pull_and_build_all everything

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,238 @@
# -*- 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.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1999 Netscape Communications Corporation. All Rights
# Reserved.
#
# Makefile for the LDAP classes
#
# An optimized compile is done by default. You can specify "DEBUG=1" on
# the make line to generate debug symbols in the bytecode.
#
# The package includes com.netscape.sasl (until there is another
# home for it)
#
# You can compile only subsets of the classes by specifying one of the
# following:
# doc
# classes
# LDAPCLASSES
# MAIN
# CLIENT
# OPERS
# UTIL
# BER
# BEANS
# SASL
# TOOLS
# FILTER
#
# Create the JAR files with the following targets:
# package
# basepackage
# filterpackage
# beanpackage
# docpackage
#
# The usual mozilla environment variable must be defined:
# MOZ_SRC (the root of your CVS tree)
#
# And the Java root directory
# JAVA_HOME
#
ARCH := $(shell uname -s)
MCOM_ROOT=.
ifeq ($(ARCH), WINNT)
MOZ_DIR:=$(subst \,/,$(MOZ_SRC))
BASEDIR:=$(MOZ_DIR)/mozilla/directory/java-sdk
else
ifeq ($(ARCH), WIN95)
MOZ_DIR:=$(subst \,/,$(MOZ_SRC))
BASEDIR:=$(MOZ_DIR)/mozilla/directory/java-sdk
else
BASEDIR := $(shell cd $(MCOM_ROOT); pwd)
endif
endif
# Destination for class files and packages
CLASS_DEST=$(BASEDIR)/dist/classes
FILTER_CLASS_DEST=$(BASEDIR)/dist/ldapfilt
# Set up the CLASSPATH automatically,
ifeq ($(ARCH), WINNT)
JDK := $(subst \,/,$(JAVA_HOME))
JAR:=$(JDK)/bin/jar
SEP=;
else
ifeq ($(ARCH), WIN95)
JDK := $(subst \,/,$(JAVA_HOME))
JAR:=$(JDK)/bin/jar
SEP=;
else
JDK := $(JAVA_HOME)
JAR:=$(JAVA_HOME)/bin/jar
SEP=:
endif
endif
JAASLIB=$(BASEDIR)/ldapjdk/lib/jaas.jar
JAVACLASSPATH:=$(BASEDIR)/ldapjdk$(SEP)$(JAASLIB)$(SEP)$(BASEDIR)/ldapbeans$(SEP)$(JDK)/lib/classes.zip$(SEP)$(CLASSPATH)
SRCDIR=netscape/ldap
BEANDIR=$(BASEDIR)/ldapbeans/netscape/ldap/beans
DISTDIR=$(MCOM_ROOT)/dist
CLASSDIR=$(MCOM_ROOT)/dist/classes
FILTERCLASSDIR=$(MCOM_ROOT)/dist/ldapfilt
CLASSPACKAGEDIR=$(DISTDIR)/packages
PACKAGENAME=javaldap.zip
ifeq ($(DEBUG), 1)
BASEPACKAGENAME=ldapjdk_debug.jar
else
BASEPACKAGENAME=ldapjdk.jar
endif
FILTERJAR=ldapfilt.jar
CLASSPACKAGE=$(CLASSPACKAGEDIR)/$(PACKAGENAME)
BEANPACKAGENAME=ldapbeans.jar
TOOLSTARGETDIR=$(DISTDIR)/tools
TOOLSDIR=$(BASEDIR)/tools
DOCDIR=$(DISTDIR)/doc
BERDOCPACKAGEDIR=$(DISTDIR)/doc/ber
DOCNAME=ldapdoc.zip
DOCPACKAGE=$(CLASSPACKAGEDIR)/$(DOCNAME)
EXAMPLEDIR=$(DISTDIR)/examples
#TESTSRCDIR=$(BASEDIR)/netsite/ldap/java/netscape/ldap/tests
ERRORSDIR=$(CLASSDIR)/netscape/ldap/errors
SASLDIR=com/netscape/sasl
SASLMECHANISMDIR=com/netscape/sasl/mechanisms
ifndef JAVADOC
JAVADOC=$(JDKBIN)javadoc -classpath "$(JAVACLASSPATH)"
endif
ifndef JAVAC
ifdef JAVA_HOME
JDKBIN=$(JDK)/bin/
endif
ifeq ($(DEBUG), 1)
JAVAC=$(JDKBIN)javac -g -classpath "$(JAVACLASSPATH)"
else
JAVAC=$(JDKBIN)javac -O -classpath "$(JAVACLASSPATH)"
endif
endif
BERDOCCLASSES=netscape.ldap.ber.stream
DOCCLASSES=netscape.ldap netscape.ldap.beans netscape.ldap.controls \
netscape.ldap.util $(TOOLSDIR)/*.java $(BERDOCCLASSES)
all: classes
basics: $(DISTDIR) $(CLASSDIR)
cp -p manifest.mf $(CLASS_DEST)
classes: LDAPCLASSES BEANS TOOLS
doc: $(DISTDIR) $(DOCDIR) DOCS
berdoc: $(DISTDIR) $(BERDOCPACKAGEDIR) BERDOCS
examples: $(DISTDIR) $(EXAMPLEDIR)/java $(EXAMPLEDIR)/js $(EXAMPLEDIR)/java/beans EXAMPLES
tests: $(CLASSDIR)
cd $(TESTSRCDIR); $(JAVAC) -d $(CLASS_DEST) *.java
package: basepackage filterpackage beanpackage docpackage
basepackage: $(CLASSPACKAGEDIR)
cd $(DISTDIR)/classes; rm -f ../packages/$(BASEPACKAGENAME); $(JAR) cvfm ../packages/$(BASEPACKAGENAME) manifest.mf netscape/ldap/*.class netscape/ldap/client/*.class netscape/ldap/client/opers/*.class netscape/ldap/ber/stream/*.class netscape/ldap/controls/*.class netscape/ldap/util/*.class netscape/ldap/errors/*.props com/netscape/sasl/*.class com/netscape/sasl/mechanisms/*.class tools/*.class
beanpackage: $(CLASSPACKAGEDIR)
cd $(DISTDIR)/classes; rm -f ../packages/$(BEANPACKAGENAME); $(JAR) cvf ../packages/$(BEANPACKAGENAME) netscape/ldap/beans
docpackage: $(DOCDIR) $(CLASSPACKAGEDIR)
cd $(DOCDIR); rm -f ../packages/$(DOCNAME); $(JAR) cvf ../packages/$(DOCNAME) *.html *.css netscape/ldap/*.html netscape/ldap/beans/*.html netscape/ldap/controls/*.html netscape/ldap/util/*.html netscape/ldap/ber/stream/*.html
MAIN: basics
cd ldapjdk/$(SRCDIR); $(JAVAC) -d "$(CLASS_DEST)" *.java
CLIENT: basics
cd ldapjdk/$(SRCDIR)/client; $(JAVAC) -d "$(CLASS_DEST)" *.java
OPERS: basics
cd ldapjdk/$(SRCDIR)/client/opers; $(JAVAC) -d "$(CLASS_DEST)" *.java
BER: basics
cd ldapjdk/$(SRCDIR)/ber/stream; $(JAVAC) -d "$(CLASS_DEST)" *.java
UTIL: basics
cd ldapjdk/$(SRCDIR)/util; $(JAVAC) -d "$(CLASS_DEST)" *.java
SASLMECHANISM: basics
cd ldapjdk/$(SASLMECHANISMDIR); $(JAVAC) -d "$(CLASS_DEST)" *.java
SASL: basics
cd ldapjdk/$(SASLDIR); $(JAVAC) -d "$(CLASS_DEST)" *.java
ERRORS: basics $(ERRORSDIR)
cp -p ldapjdk/$(SRCDIR)/errors/*.props $(ERRORSDIR)
CONTROLS: basics
cd ldapjdk/$(SRCDIR)/controls; $(JAVAC) -d "$(CLASS_DEST)" *.java
LDAPCLASSES: BER OPERS CLIENT MAIN UTIL CONTROLS ERRORS SASL SASLMECHANISM
BEANS: OTHERBEANS
OTHERBEANS: basics
cd ldapbeans/$(SRCDIR)/beans; $(JAVAC) -d "$(CLASS_DEST)" *.java
TOOLS: basics
cd tools; $(JAVAC) -d "$(CLASS_DEST)" *.java
FILTER: $(FILTERCLASSDIR)
cd ldapfilter/netscape/ldap/util; $(JAVAC) -d "$(FILTER_CLASS_DEST)" *.java
filterpackage: $(CLASSPACKAGEDIR)
cd "$(FILTER_CLASS_DEST)"; rm -f ../packages/$(FILTERJAR); $(JAR) cvf ../packages/$(FILTERJAR) netscape/ldap/util/*.class
DOCS:
$(JAVADOC) -d $(DOCDIR) $(DOCCLASSES)
BERDOCS:
$(JAVADOC) -d $(BERDOCPACKAGEDIR) $(BERDOCCLASSES)
EXAMPLES:
-cp -p $(EXAMPLESRCDIR)/java/* $(EXAMPLEDIR)/java
-cp -p $(EXAMPLESRCDIR)/java/beans/* $(EXAMPLEDIR)/java/beans
-cp -p $(EXAMPLESRCDIR)/java/beans/makejars.* $(CLASSDIR)
-cp -p $(EXAMPLESRCDIR)/js/* $(EXAMPLEDIR)/js
clean:
rm -rf $(DISTDIR)
$(CLASSPACKAGEDIR):
mkdir -p $@
$(DOCDIR):
mkdir -p $@
$(DISTDIR):
mkdir -p $@
$(CLASSDIR):
mkdir -p $@
$(ERRORSDIR):
mkdir -p $@
$(FILTERCLASSDIR):
mkdir -p $@

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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap.beans;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.io.Serializable;
public class DisplayString extends TextArea implements Serializable {
public DisplayString() {
super();
setEditable(false);
}
public void reportChange(PropertyChangeEvent evt) {
Object obj = (Object)evt.getNewValue();
if (obj == null) {
append("null\n");
return;
}
String[] values = null;
if (obj instanceof String) {
values = new String[1];
values[0] = (String)obj;
}
else
values = (String[])obj;
int width = getSize().width - 10;
Font f = getFont();
for (int i=0; i<values.length; i++) {
String text = values[i];
if (f != null) {
// Trim the text to fit.
FontMetrics fm = getFontMetrics(f);
while (fm.stringWidth(text) > width) {
text = text.substring(0, text.length()-1);
}
}
append(text+'\n');
}
}
public void clear (ActionEvent e) {
setText("");
invalidate();
repaint();
}
}

View File

@@ -0,0 +1,4 @@
Name: netscape/ldap/beans/DisplayString.class
Java-Bean: True
Name: netscape/ldap/beans/DisplayStringBeanInfo.class

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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap.beans;
import java.beans.SimpleBeanInfo;
import java.beans.BeanDescriptor;
import java.beans.EventSetDescriptor;
import java.beans.MethodDescriptor;
import java.beans.PropertyDescriptor;
import java.beans.ParameterDescriptor;
import java.beans.BeanInfo;
/**
* BeanInfo for displaying string
*
*/
public class DisplayStringBeanInfo extends SimpleBeanInfo {
public DisplayStringBeanInfo() throws Exception {
beanClass = Class.forName( "netscape.ldap.beans.DisplayString" );
// Publish descriptor ---------------------------------------------
try {
_beanDescriptor = new BeanDescriptor(beanClass);
_beanDescriptor.setDisplayName( "Text Field" );
_beanDescriptor.setShortDescription(
"LDAP property retrieval -"
+ " provided a host, port, base, search filter,"
+ " and optionally a username and password,"
+ " return an array of string values both as a"
+ " function return and as a Property change event." );
} catch (Exception e) {
}
}
public BeanDescriptor getBeanDescriptor() {
return _beanDescriptor;
}
private static Class beanClass;
private BeanDescriptor _beanDescriptor;
private EventSetDescriptor[] _eventSetDescriptor;
private PropertyDescriptor[] _propertyDescriptor;
}

View File

@@ -0,0 +1,391 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap.beans;
import netscape.ldap.*;
import java.util.StringTokenizer;
// This class has a bound property
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;
/**
* This is a base class that is extended by various specialized LDAP
* Beans. It provides the common properties and accessors used by
* them.
*/
public class LDAPBasePropertySupport implements Serializable {
/**
* Constructor with no parameters
*/
public LDAPBasePropertySupport() {}
/**
* Returns the host to search at.
* @return DNS name or dotted IP name of host to search at
*/
public String getHost() {
return _host;
}
/**
* Sets host string.
* @param theHost host name
*/
public void setHost( String theHost ) {
_host = theHost;
}
/**
* Returns the port to search at.
* @return Port to search at
*/
public int getPort() {
return _port;
}
/**
* Sets port number.
* @param thePort port
*/
public void setPort( int thePort ) {
_port = thePort;
}
/**
* Returns the directory base to search at.
* @return directory base to search
*/
public String getBase() {
return _base;
}
/**
* Sets the starting base
* @param theBase starting base
*/
public void setBase( String theBase ) {
_base = theBase;
}
/**
* Returns the DN to authenticate as; null or empty for anonymous.
* @return DN to authenticate as
*/
public String getAuthDN() {
return _authDN;
}
/**
* Sets the DN to authenticate as; null or empty for anonymous.
* @param authDN the DN to authenticate as
*/
public void setAuthDN( String authDN ) {
this._authDN = authDN;
}
/**
* Returns the password for the DN to authenticate as
* @return Password of DN to authenticate as
*/
public String getAuthPassword() {
return _authPassword;
}
/**
* Sets the password for the DN to authenticate as
* @param authPassword the password to use in authentication
*/
public void setAuthPassword( String authPassword ) {
this._authPassword = authPassword;
}
/**
* Returns the user name
* @return The user name
*/
public String getUserName() {
return _userName;
}
/**
* Set the user name. The name should be of the form "Polly Plum".
* @param name The user name
*/
public void setUserName( String name ) {
_userName = name;
}
/**
* Return the user ID.
* @return name the user id
*/
public String getUserID() {
return _userID;
}
/**
* Set the user ID.
* @param name the value of the user id
*/
public void setUserID( String name ) {
_userID = name;
}
/**
* Get the current search scope
* @return the current search scope as integer
*/
public int getScope() {
return _scope;
}
/**
* Set the search scope using an integer
* @param scope one of LDAPConnection.SCOPE_BASE,
* LDAPConnection.SCOPE_SUB, LDAPConnection.SCOPE_ONE
*/
public void setScope( int scope ) {
_scope = scope;
}
/**
* Returns the search filter
* @return search filter
*/
public String getFilter() {
return _filter;
}
/**
* Sets the search filter
* @param filter search filter
*/
public void setFilter( String filter ) {
_filter = filter;
}
/**
* Returns true if debug output is on
* @return true if debug output is on
*/
public boolean getDebug() {
return _debug;
}
/**
* Turns debug output on or off
* @param on true for debug output
*/
public void setDebug( boolean on ) {
_debug = on;
}
/**
* Returns the latest error code
* @return The latest error code
*/
public int getErrorCode() {
return _errCode;
}
/**
* Sets an error code for retrieval by a client
* @param code An error code
*/
public void setErrorCode( int code ) {
_errCode = code;
}
/**
* Add a client to be notified when an authentication result is in
* @param listener a client to be notified of changes
*/
public void addPropertyChangeListener( PropertyChangeListener listener ) {
printDebug( "Adding listener " + listener );
m_propSupport.addPropertyChangeListener( listener );
}
/**
* Remove a client which had requested notification on authentication
* @param listener a client to not be notified of changes
*/
public void removePropertyChangeListener(
PropertyChangeListener listener ) {
m_propSupport.removePropertyChangeListener( listener );
}
/**
* Support for bound property notification
* @param propName Name of changed property
* @param oldValue Previous value of property
* @param newValue New value of property
*/
public void firePropertyChange(
String propName,
Object oldValue,
Object newValue ) {
if (m_propSupport == null)
m_propSupport = new PropertyChangeSupport( this );
m_propSupport.firePropertyChange( propName, oldValue, newValue );
}
protected void printDebug( String s ) {
if ( _debug )
System.out.println( s );
}
/**
* Sets up basic connection privileges for Communicator if necessary,
* and connects
* @param host Host to connect to.
* @param port Port number.
* @exception LDAPException from connect()
*/
protected void connect( LDAPConnection conn, String host, int port )
throws LDAPException {
boolean needsPrivileges = true;
/* Running standalone? */
SecurityManager sec = System.getSecurityManager();
printDebug( "Security manager = " + sec );
if ( sec == null ) {
printDebug( "No security manager" );
/* Not an applet, we can do what we want to */
needsPrivileges = false;
/* Can't do instanceof on an abstract class */
} else if ( sec.toString().startsWith("java.lang.NullSecurityManager") ) {
printDebug( "No security manager" );
/* Not an applet, we can do what we want to */
needsPrivileges = false;
} else if ( sec.toString().startsWith(
"netscape.security.AppletSecurity" ) ) {
/* Connecting to the local host? */
try {
if ( host.equalsIgnoreCase(
java.net.InetAddress.getLocalHost().getHostName() ) )
needsPrivileges = false;
} catch ( java.net.UnknownHostException e ) {
}
}
if ( needsPrivileges ) {
/* Running as applet. Is PrivilegeManager around? */
String mgr = "netscape.security.PrivilegeManager";
try {
Class c = Class.forName( mgr );
java.lang.reflect.Method[] m = c.getMethods();
if ( m != null ) {
for( int i = 0; i < m.length; i++ ) {
if ( m[i].getName().equals( "enablePrivilege" ) ) {
try {
Object[] args = new Object[1];
args[0] = new String( "UniversalConnect" );
m[i].invoke( null, args );
printDebug( "UniversalConnect enabled" );
args[0] = new String( "UniversalPropertyRead" );
m[i].invoke( null, args );
printDebug( "UniversalPropertyRead enabled" );
} catch ( Exception e ) {
printDebug( "Exception on invoking " +
"enablePrivilege: " +
e.toString() );
break;
}
break;
}
}
}
} catch ( ClassNotFoundException e ) {
printDebug( "no " + mgr );
}
}
conn.connect( host, port );
setDefaultReferralCredentials( conn );
}
protected void setDefaultReferralCredentials(
LDAPConnection conn ) {
final LDAPConnection m_conn = conn;
LDAPRebind rebind = new LDAPRebind() {
public LDAPRebindAuth getRebindAuthentication(
String host,
int port ) {
return new LDAPRebindAuth(
m_conn.getAuthenticationDN(),
m_conn.getAuthenticationPassword() );
}
};
try {
conn.setOption(LDAPConnection.REFERRALS, Boolean.TRUE);
conn.setOption(LDAPConnection.REFERRALS_REBIND_PROC, rebind);
} catch (LDAPException e) {
//will never happen
}
}
/**
* Utility method to convert an array of Strings to a single String
* with line feeds between elements.
* @param aResult The array of Strings to convert
* @return A String with the elements separated by line feeds
*/
public String convertToString( String[] aResult ) {
String sResult = "";
if ( null != aResult ) {
for ( int i = 0; i < aResult.length; i++ ) {
sResult += aResult[i] + "\n";
}
}
return sResult;
}
/*
* Variables
*/
/* Error codes from search operations, etc */
public static final int OK = 0;
public static final int INVALID_PARAMETER = 1;
public static final int CONNECT_ERROR = 2;
public static final int AUTHENTICATION_ERROR = 3;
public static final int PROPERTY_NOT_FOUND = 4;
public static final int AMBIGUOUS_RESULTS = 5;
public static final int NO_SUCH_OBJECT = 6;
private boolean _debug = false;
private int _errCode = 0;
private String _host = new String("localhost");
private int _port = 389;
private int _scope = LDAPConnection.SCOPE_SUB;
private String _base = new String("");
private String _filter = new String("");
private String _authDN = new String("");
private String _authPassword = new String("");
private String _userName = new String("");
private String _userID = new String("");
transient private PropertyChangeSupport m_propSupport =
new PropertyChangeSupport( this );
}

View File

@@ -0,0 +1,358 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap.beans;
import netscape.ldap.*;
import netscape.ldap.beans.LDAPBasePropertySupport;
import java.util.Enumeration;
import java.util.Vector;
import java.io.Serializable;
import java.awt.event.*;
/**
* Invisible Bean that just takes a host, port, directory base,
* search string, and optional authentication name and password,
* and returns a list of all matching DNs. The search has the scope
* "SUB", which means that it will find an entry anywhere at or
* below the directory base, unless a different scope is specified.
* <BR><BR>
* Optionally, a client can register as a PropertyChangeListener
* and will be notified when the values are available.
*<BR><BR>
* A null result means no matching DNs were found. The reason is
* available through getErrorCode(), which returns one of
* the following:
*<PRE>
* OK
* INVALID_PARAMETER
* CONNECT_ERROR
* AUTHENTICATION_ERROR
* PROPERTY_NOT_FOUND
* AMBIGUOUS_RESULTS
*</PRE>
*
*/
public class LDAPGetEntries extends LDAPBasePropertySupport implements Serializable {
/**
* Constructor with no parameters
*/
public LDAPGetEntries() {
super();
}
/**
* Constructor with host, port, and base initializers
* @param theHost host string
* @param thePort port number
* @param theBase directory base string
*/
public LDAPGetEntries( String theHost, int thePort, String theBase ) {
setHost( theHost );
setPort( thePort );
setBase( theBase );
}
/**
* Constructor with host, port, base, and scope initializers
* @param theHost host string
* @param thePort port number
* @param theBase directory base string
* @param theScope one of LDAPConnection.SCOPE_BASE,
* LDAPConnection.SCOPE_SUB, LDAPConnection.SCOPE_ONE
*/
public LDAPGetEntries( String theHost,
int thePort,
String theBase,
int theScope ) {
setHost( theHost );
setPort( thePort );
setBase( theBase );
setScope( theScope );
}
private void notifyResult( String error ) {
firePropertyChange( "error", _errorMsg, error );
_errorMsg = error;
}
private void notifyResult( String[] newResult ) {
String sNewResult = convertToString( newResult );
firePropertyChange( "result", _result, newResult );
_sResult = sNewResult;
_result = newResult;
}
/**
* Returns the name of the attribute to retrieve
* @return attribute name to retrieve
*/
public String getAttribute() {
return _attribute;
}
/**
* Sets the attribute to retrieve
*/
public void setAttribute( String attr ) {
_attribute = attr;
}
public void setResultString( String sNewValue ) {
_sResult = sNewValue;
}
public String getResultString() {
return _sResult;
}
/**
* Searches and returns values for a specified attribute
* @param host host string
* @param port port number
* @param base directory base string
* @param scope one of LDAPConnection.SCOPE_BASE,
* LDAPConnection.SCOPE_SUB, LDAPConnection.SCOPE_ONE
* @param filter search filter
* @param attribute name of property to return values for
* @return Array of values for the property
*/
public String[] getEntries( String host,
int port,
String base,
int scope,
String filter) {
setHost( host );
setPort( port );
setBase( base );
setScope( scope );
setFilter( filter );
return getEntries();
}
/**
* Searches and returns values for a specified attribute
* @param host host string
* @param port port number
* @param base directory base string
* @param scope one of LDAPConnection.SCOPE_BASE,
* LDAPConnection.SCOPE_SUB, LDAPConnection.SCOPE_ONE
* @param userName The user name
* @param userid The user id
* @return Array of DNs
*/
public String[] getEntries( String host,
int port,
String base,
int scope,
String userid,
String userName) {
setHost( host );
setPort( port );
setBase( base );
setScope( scope );
if (userName == null)
userName = new String("");
setUserName( userName );
if (userid == null)
userid = new String("");
setUserID( userid );
return getEntries();
}
// Added this method in order to get exposed in BDK
public void getEntries(ActionEvent x) {
getEntries();
}
/**
* Searches and returns values of a previously registered property,
* using previously set parameters
* @return Array of values for the property
*/
public String[] getEntries() {
boolean invalid = false;
if ((getUserName().length() < 1) && (getUserID().length() < 1) &&
(getFilter().length() < 1)) {
printDebug("No user name or user ID");
invalid = true;
} else if ( (getHost().length() < 1) || (getBase().length() < 1) ) {
printDebug( "Invalid host name or search base" );
invalid = true;
}
if ( invalid ) {
setErrorCode( INVALID_PARAMETER );
notifyResult( (String)null);
return null;
}
if (getFilter().length() < 1) {
String filter = new String("");
if ((getUserName().length() > 1) && (getUserID().length() > 1)) {
filter = "(|(cn="+getUserName()+")(uid="+getUserID()+"))";
} else if (getUserName().length() > 1) {
filter = "cn="+getUserName();
} else if (getUserID().length() > 1) {
filter = "uid="+getUserID();
}
setFilter(filter);
}
String[] res = null;
LDAPConnection m_ldc = new LDAPConnection();
try {
try {
printDebug("Connecting to " + getHost() +
" " + getPort());
connect( m_ldc, getHost(), getPort());
} catch (Exception e) {
printDebug( "Failed to connect to " + getHost() + ": " +
e.toString() );
setErrorCode( CONNECT_ERROR );
notifyResult( (String)null );
m_ldc = null;
throw( new Exception() );
}
// Authenticate?
if ( (!getAuthDN().equals("")) &&
(!getAuthPassword().equals("")) ) {
printDebug( "Authenticating " + getAuthDN() );
try {
m_ldc.authenticate( getAuthDN(), getAuthPassword() );
} catch (Exception e) {
printDebug( "Failed to authenticate: " + e.toString() );
setErrorCode( AUTHENTICATION_ERROR );
notifyResult( (String)null );
throw( new Exception() );
}
}
// Search
try {
printDebug("Searching " + getBase() +
" for " + getFilter() + ", scope = " + getScope());
String[] attrs = { _attribute };
LDAPSearchResults results = m_ldc.search( getBase(),
getScope(),
getFilter(),
attrs,
false);
// Create a vector for the results
Vector v = new Vector();
LDAPEntry entry = null;
while ( results.hasMoreElements() ) {
try {
entry = results.next();
} catch (LDAPException e) {
if (getDebug())
notifyResult(e.toString());
continue;
}
// Add the DN to the list
String value = "";
if ( _attribute.equals("dn") ) {
value = entry.getDN();
} else {
LDAPAttribute attr = entry.getAttribute( _attribute );
if ( attr != null ) {
Enumeration vals = attr.getStringValues();
if ( (vals != null) && (vals.hasMoreElements()) ) {
value = (String)vals.nextElement();
}
}
}
v.addElement( value );
printDebug( "... " + value );
}
// Pull out the DNs and create a string array
if ( v.size() > 0 ) {
res = new String[v.size()];
v.copyInto( res );
v.removeAllElements();
setErrorCode( OK );
} else {
printDebug( "No entries found for " + getFilter() );
setErrorCode( PROPERTY_NOT_FOUND );
}
} catch (Exception e) {
if (getDebug()) {
printDebug( "Failed to search for " + getFilter() + ": " +
e.toString() );
}
setErrorCode( PROPERTY_NOT_FOUND );
}
} catch (Exception e) {
}
// Disconnect
try {
if ( (m_ldc != null) && m_ldc.isConnected() )
m_ldc.disconnect();
} catch ( Exception e ) {
}
// Notify any clients with a PropertyChangeEvent
notifyResult( res );
return res;
}
/**
* The main body if we run it as application instead of applet.
* @param args list of arguments
*/
public static void main(String args[]) {
String[] scope = { "base", "one", "sub" };
int scopeIndex = -1;
for( int i = 0; (i < scope.length) && (args.length == 5); i++ ) {
if ( args[3].equalsIgnoreCase(scope[i]) ) {
scopeIndex = i;
break;
}
}
if ( scopeIndex < 0 ) {
System.out.println( "Usage: LDAPGetEntries host port base" +
" scope filter" );
System.exit(1);
}
LDAPGetEntries app = new LDAPGetEntries();
app.setHost( args[0] );
app.setPort( java.lang.Integer.parseInt( args[1] ) );
app.setBase( args[2] );
app.setScope( scopeIndex );
app.setFilter( args[4] );
String[] response = app.getEntries();
if ( response != null ) {
for( int i = 0; i < response.length; i++ )
System.out.println( "\t" + response[i] );
}
System.exit(0);
}
/*
* Variables
*/
private String _attribute = "dn";
private String[] _result;
private String _sResult = null;
private String _errorMsg = null;
}

View File

@@ -0,0 +1,7 @@
Name: netscape/ldap/beans/LDAPGetEntries.class
Java-Bean: True
Name: netscape/ldap/beans/LDAPBasePropertySupport.class
Name: netscape/ldap/beans/LDAPGetEntriesBeanInfo.class

View File

@@ -0,0 +1,129 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap.beans;
import java.beans.SimpleBeanInfo;
import java.beans.BeanDescriptor;
import java.beans.EventSetDescriptor;
import java.beans.MethodDescriptor;
import java.beans.PropertyDescriptor;
import java.beans.ParameterDescriptor;
import java.beans.BeanInfo;
/**
* BeanInfo for LDAPGetEntries
*/
public class LDAPGetEntriesBeanInfo extends SimpleBeanInfo {
public LDAPGetEntriesBeanInfo() throws Exception {
beanClass = Class.forName( "netscape.ldap.beans.LDAPGetEntries" );
try {
PropertyDescriptor host =
new PropertyDescriptor("host", beanClass);
PropertyDescriptor port =
new PropertyDescriptor("port", beanClass);
PropertyDescriptor authDN =
new PropertyDescriptor("authDN", beanClass);
PropertyDescriptor authPassword =
new PropertyDescriptor("authPassword", beanClass);
PropertyDescriptor base =
new PropertyDescriptor("base", beanClass);
PropertyDescriptor userName =
new PropertyDescriptor("userName", beanClass);
PropertyDescriptor userID =
new PropertyDescriptor("userID", beanClass);
PropertyDescriptor filter =
new PropertyDescriptor("filter", beanClass);
PropertyDescriptor scope =
new PropertyDescriptor("scope", beanClass);
PropertyDescriptor debug =
new PropertyDescriptor("debug", beanClass);
PropertyDescriptor rv[] =
{host, port, authDN, authPassword, base, filter,
scope, userName, userID, debug};
_propertyDescriptor = new PropertyDescriptor[rv.length];
for( int i = 0; i < rv.length; i++ )
_propertyDescriptor[i] = rv[i];
} catch (Exception e) {
throw new Error(e.toString());
}
// Publish events --------------------------------------------------
try {
_eventSetDescriptor = new EventSetDescriptor[1];
_eventSetDescriptor[0] = new EventSetDescriptor(beanClass,
"propertyChange",
Class.forName("java.beans.PropertyChangeListener"),
"propertyChange");
} catch (Exception e) {
throw new Error(e.toString());
}
// Publish descriptor ---------------------------------------------
try {
_beanDescriptor = new BeanDescriptor(beanClass);
_beanDescriptor.setDisplayName( "LDAP entry retrieval" );
_beanDescriptor.setShortDescription(
"LDAP property retrieval -"
+ " provided a host, port, base, search filter,"
+ " and optionally a username and password,"
+ " return an array of string values both as a"
+ " function return and as a Property change event." );
} catch (Exception e) {
}
}
/**
* @return the public properties
*/
public PropertyDescriptor[] getPropertyDescriptors() {
return _propertyDescriptor;
}
public EventSetDescriptor[] getEventSetDescriptors() {
return _eventSetDescriptor;
}
public BeanInfo[] getAdditionalBeanInfo() {
return null;
}
public int getDefaultEventIndex() {
return -1;
}
public int getDefaultPropertyIndex() {
return -1;
}
public BeanDescriptor getBeanDescriptor() {
return _beanDescriptor;
}
private static Class beanClass;
private BeanDescriptor _beanDescriptor;
private EventSetDescriptor[] _eventSetDescriptor;
private PropertyDescriptor[] _propertyDescriptor;
}

View File

@@ -0,0 +1,332 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap.beans;
import netscape.ldap.*;
import netscape.ldap.beans.LDAPBasePropertySupport;
import java.util.Enumeration;
import java.util.Vector;
import java.io.Serializable;
import java.beans.*;
import java.awt.event.*;
/**
* Invisible Bean that just takes a name and password, host and
* port, and directory base and attribute name, and returns an
* attribute's values from a Directory Server. The values are
* assumed to be strings, and are returned as an array. The
* search has the scope "SUB", which means that it will find
* an entry anywhere at or below the directory base.
* <BR><BR>
* Optionally, a client can register as a PropertyChangeListener
* and will be notified when the values are available.
*<BR><BR>
* A null result means the property fetch failed. The reason is
* available through getErrorCode(), which returns one of
* the following:
*<PRE>
* OK
* INVALID_PARAMETER
* CONNECT_ERROR
* AUTHENTICATION_ERROR
* PROPERTY_NOT_FOUND
* AMBIGUOUS_RESULTS
*</PRE>
*/
public class LDAPGetProperty extends LDAPBasePropertySupport implements
Serializable {
/**
* Constructor with no parameters
*/
public LDAPGetProperty() {}
/**
* Constructor with host, port, and base initializers
* @param theHost host string
* @param thePort port number
* @param theBase directory base string
*/
public LDAPGetProperty( String theHost, int thePort, String theBase ) {
setHost( theHost );
setPort( thePort );
setBase( theBase );
}
/**
* Returns the name of the attribute to retrieve
* @return attribute name to retrieve
*/
public String getAttribute() {
return _attribute;
}
/**
* Sets the attribute to retrieve
*/
public void setAttribute( String attr ) {
_attribute = attr;
}
private void notifyResult( String[] newResult ) {
String sNewResult = convertToString( newResult );
firePropertyChange( "result", _result, newResult );
_sResult = sNewResult;
_result = newResult;
}
private void notifyResult( Vector newResult ) {
firePropertyChange( "result", _resultV, newResult );
_resultV = (Vector)newResult.clone();
}
private void notifyResult( String error ) {
firePropertyChange( "error", _errorMsg, error );
_errorMsg = error;
}
public void setDNs(PropertyChangeEvent evt) {
Object obj = (Object)evt.getNewValue();
if ((obj != null) && (obj instanceof String[])) {
String[] strings = (String[])obj;
if (strings.length == 0)
return;
_dns = new String[strings.length];
System.arraycopy(obj, 0, _dns, 0, strings.length);
System.out.println("length of dns -> "+_dns.length);
}
}
/**
* Searches and returns values for a specified attribute
* @param host host string
* @param port port number
* @param base directory base string
* @param filter search filter
* @param attribute name of property to return values for
* @return Array of values for the property
*/
public String[] getProperty( String host, int port, String base,
String filter, String attribute) {
setHost( host );
setPort( port );
setBase( base );
setFilter( filter );
setAttribute( attribute );
return getProperty();
}
// Added this method in order to get exposed in BDK
public void getProperty(ActionEvent x) {
getProperty();
}
/**
* Searches and returns values of a previously registered property,
* using previously set parameters
* @return Array of values for the property
*/
public String[] getProperty() {
if ( (_attribute.length() < 1) || (getFilter().length() < 1) ) {
printDebug( "Invalid attribute name or filter" );
setErrorCode( INVALID_PARAMETER );
notifyResult( (String[])null );
return null;
}
String[] res = null;
LDAPConnection m_ldc;
try {
m_ldc = new LDAPConnection();
printDebug("Connecting to " + getHost() +
" " + getPort());
connect( m_ldc, getHost(), getPort());
} catch (Exception e) {
printDebug( "Failed to connect to " + getHost() + ": "
+ e.toString() );
setErrorCode( CONNECT_ERROR );
notifyResult( (String[])null );
return null;
}
// Authenticate?
if (_dns != null) {
for (int i=0; i<_dns.length; i++) {
try {
m_ldc.authenticate(_dns[i], getAuthPassword());
break;
} catch (Exception e) {
if (i == _dns.length-1) {
printDebug( "Failed to authenticate to " +
getHost() + ": " + e.toString() );
setErrorCode( AUTHENTICATION_ERROR );
notifyResult( (String[])null );
return null;
}
}
}
} else if ( (!getAuthDN().equals("")) && (!getAuthPassword().equals("")) ) {
printDebug( "Authenticating " + getAuthDN() + " - " +
getAuthPassword() );
try {
m_ldc.authenticate( getAuthDN(), getAuthPassword() );
} catch (Exception e) {
printDebug( "Failed to authenticate to " +
getHost() + ": " + e.toString() );
setErrorCode( AUTHENTICATION_ERROR );
notifyResult( (String[])null );
return null;
}
}
int numDataEntries = 0;
// Search
try {
String[] attrs = new String[1];
attrs[0] = _attribute;
LDAPSearchResults results = m_ldc.search(getBase(),
getScope(),
getFilter(),
attrs, false);
// Should be only one result, at most
LDAPEntry currEntry = null;
LDAPEntry entry = null;
while ( results.hasMoreElements() ) {
try {
currEntry = results.next();
if (numDataEntries == 0)
entry = currEntry;
if (++numDataEntries > 1) {
printDebug( "More than one entry found for " +
getFilter() );
setErrorCode( AMBIGUOUS_RESULTS );
break;
}
} catch (LDAPException e) {
if (getDebug())
notifyResult(e.toString());
continue;
}
}
if (numDataEntries == 1) {
printDebug( "... " + entry.getDN() );
// Good - exactly one entry found; get the attribute
// Treat DN as a special case
if ( _attribute.equalsIgnoreCase( "dn" ) ) {
res = new String[1];
res[0] = entry.getDN();
setErrorCode( OK );
} else {
LDAPAttributeSet attrset = entry.getAttributeSet();
Enumeration attrsenum = attrset.getAttributes();
if (attrsenum.hasMoreElements()) {
LDAPAttribute attr =
(LDAPAttribute)attrsenum.nextElement();
printDebug( attr.getName() + " = " );
// Get the values as strings
Enumeration valuesenum = attr.getStringValues();
if (valuesenum != null) {
// Create a string array for the results
Vector v = new Vector();
while (valuesenum.hasMoreElements()) {
String val = (String)valuesenum.nextElement();
v.addElement( val );
printDebug( "\t\t" + val );
}
res = new String[v.size()];
v.copyInto( res );
setErrorCode( OK );
} else {
Enumeration byteEnum = attr.getByteValues();
Vector v = new Vector();
while (byteEnum.hasMoreElements()) {
byte[] val = (byte[])byteEnum.nextElement();
v.addElement( val );
printDebug( "\t\t" + val );
}
setErrorCode( OK );
notifyResult(v);
return (res = null);
}
} else {
printDebug( "No properties found for " +
_attribute );
setErrorCode( PROPERTY_NOT_FOUND );
}
}
}
} catch (Exception e) {
if (getDebug()) {
printDebug( "Failed to search for " + getFilter() + ": "
+ e.toString() );
}
setErrorCode( PROPERTY_NOT_FOUND );
}
if (numDataEntries == 0) {
printDebug( "No entries found for " + getFilter() );
setErrorCode( PROPERTY_NOT_FOUND );
}
// Disconnect
try {
if ( (m_ldc != null) && m_ldc.isConnected() )
m_ldc.disconnect();
} catch ( Exception e ) {
}
notifyResult( res );
return res;
}
/**
* The main body if we run it as application instead of applet.
* @param args list of arguments
*/
public static void main(String args[]) {
if (args.length != 5) {
System.out.println( "Usage: LDAPGetProperty host port base" +
" filter attribute" );
System.exit(1);
}
LDAPGetProperty app = new LDAPGetProperty();
app.setHost( args[0] );
app.setPort( java.lang.Integer.parseInt( args[1] ) );
app.setBase( args[2] );
app.setFilter( args[3] );
app.setAttribute( args[4] );
String[] response = app.getProperty();
if ( response != null ) {
for( int i = 0; i < response.length; i++ )
System.out.println( "\t" + response[i] );
}
System.exit(0);
}
/*
* Variables
*/
private String[] _dns = null;
private String _attribute = new String("cn");
transient private String[] _result;
private Vector _resultV = null;
private String _sResult = null;
private String _errorMsg = null;
}

View File

@@ -0,0 +1,6 @@
Name: netscape/ldap/beans/LDAPGetProperty.class
Java-Bean: True
Name: netscape/ldap/beans/LDAPBasePropertySupport.class
Name: netscape/ldap/beans/LDAPGetPropertyBeanInfo.class

View File

@@ -0,0 +1,138 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap.beans;
import java.beans.SimpleBeanInfo;
import java.beans.BeanDescriptor;
import java.beans.EventSetDescriptor;
import java.beans.MethodDescriptor;
import java.beans.PropertyDescriptor;
import java.beans.ParameterDescriptor;
import java.beans.BeanInfo;
/**
* BeanInfo for LDAPGetProperty
*/
public class LDAPGetPropertyBeanInfo extends SimpleBeanInfo {
public LDAPGetPropertyBeanInfo() throws Exception {
beanClass = Class.forName( "netscape.ldap.beans.LDAPGetProperty" );
try {
PropertyDescriptor host =
new PropertyDescriptor("host", beanClass);
PropertyDescriptor port =
new PropertyDescriptor("port", beanClass);
PropertyDescriptor authDN =
new PropertyDescriptor("authDN", beanClass);
PropertyDescriptor authPassword =
new PropertyDescriptor("authPassword", beanClass);
PropertyDescriptor base =
new PropertyDescriptor("base", beanClass);
PropertyDescriptor filter =
new PropertyDescriptor("filter", beanClass);
PropertyDescriptor scope =
new PropertyDescriptor("scope", beanClass);
PropertyDescriptor attribute =
new PropertyDescriptor("attribute", beanClass);
PropertyDescriptor debug =
new PropertyDescriptor("debug", beanClass);
PropertyDescriptor rv[] =
{host, port, authDN, authPassword, base, scope, attribute,
filter, debug};
_propertyDescriptor = new PropertyDescriptor[rv.length];
for( int i = 0; i < rv.length; i++ )
_propertyDescriptor[i] = rv[i];
} catch (Exception e) {
throw new Error(e.toString());
}
// Publish events --------------------------------------------------
try {
_eventSetDescriptor = new EventSetDescriptor[1];
_eventSetDescriptor[0] = new EventSetDescriptor(beanClass,
"propertyChange",
Class.forName("java.beans.PropertyChangeListener"),
"propertyChange");
} catch (Exception e) {
throw new Error(e.toString());
}
// Publish descriptor ---------------------------------------------
try {
_beanDescriptor = new BeanDescriptor(beanClass);
_beanDescriptor.setDisplayName( "LDAP property retrieval" );
_beanDescriptor.setShortDescription(
"LDAP property retrieval -"
+ " provided a host, port, base, search filter,"
+ " and optionally a username and password,"
+ " return an array of string values both as a"
+ " function return and as a Property change event." );
} catch (Exception e) {
}
}
/**
* @return the public properties
*/
public PropertyDescriptor[] getPropertyDescriptors() {
return _propertyDescriptor;
}
/**
* @return the public methods
*/
public MethodDescriptor[] getMethodDescriptors() {
return _methodDescriptor;
}
public EventSetDescriptor[] getEventSetDescriptors() {
return _eventSetDescriptor;
}
public BeanInfo[] getAdditionalBeanInfo() {
return null;
}
public int getDefaultEventIndex() {
return -1;
}
public int getDefaultPropertyIndex() {
return -1;
}
public BeanDescriptor getBeanDescriptor() {
return _beanDescriptor;
}
private static Class beanClass;
private BeanDescriptor _beanDescriptor;
private EventSetDescriptor[] _eventSetDescriptor;
private MethodDescriptor[] _methodDescriptor;
private PropertyDescriptor[] _propertyDescriptor;
}

View File

@@ -0,0 +1,433 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap.beans;
import netscape.ldap.*;
import netscape.ldap.util.*;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.io.Serializable;
import java.awt.event.*;
/**
* Invisible Bean that just takes a host and port, optional
* authentication name and password, and DN of a group and another DN
* which might be a member of the group, and returns true or
* false, depending on whether the second DN is a member of the first.
* <BR>
* Also handles the case of dynamic groups by derefencing the URL
* and searching for membership based on the url search.
* <BR>
* It doesn't handle nested groups.
* <BR><BR>
* A false result means the member could not be identified as
* belonging to the group. The exact reason is
* available through getErrorCode(), which returns one of
* the following:
*<PRE>
* OK
* INVALID_PARAMETER
* CONNECT_ERROR
* AUTHENTICATION_ERROR
* PROPERTY_NOT_FOUND
* AMBIGUOUS_RESULTS
* NO_SUCH_OBJECT
*</PRE>
*/
public class LDAPIsMember extends LDAPBasePropertySupport
implements Serializable {
/**
* Constructor with no parameters
*/
public LDAPIsMember() {}
/**
* Constructor with host, port, and group DN initializers
* @param host host string
* @param port port number
* @param group distinguished name of the group
*/
public LDAPIsMember( String host, int port, String group ) {
setHost( host );
setPort( port );
setGroup( group );
}
/**
* Constructor with host, port, authentication DN and password
* and group DN initializers
* @param host host string
* @param port port number
* @param dn fully qualified distinguished name to authenticate
* @param password password for authenticating the dn
* @param group distinguished name of the group
*/
public LDAPIsMember( String host, int port,
String dn, String password, String theGroup ) {
setHost( host );
setPort( port );
setGroup( theGroup );
setAuthDN( dn );
setAuthPassword( password );
}
private void notifyResult( String newResult ) {
firePropertyChange( "result", _result, newResult );
_result = newResult;
}
/**
* Checks if an entity (specified by distinguished name) is a
* member of a particular group (specified by distinguished name)
* @return true if the specified member belongs to the group
*/
public boolean isMember() {
String host = getHost();
int port = getPort();
String dn = getAuthDN();
String password = getAuthPassword();
String group = getGroup();
String member = getMember();
_result = new String("");
if ( (host == null) || (host.length() < 1) ) {
printDebug( "Invalid host name" );
setErrorCode( INVALID_PARAMETER );
notifyResult(null);
return false;
}
if ( (member == null) || (group == null) ||
(member.length() < 1) || (group.length() < 1) ) {
printDebug( "Invalid member or group name" );
setErrorCode( INVALID_PARAMETER );
notifyResult(null);
return false;
}
LDAPConnection m_ldc;
boolean isMember = false;
try {
m_ldc = new LDAPConnection();
printDebug("Connecting to " + host +
" " + port);
connect( m_ldc, getHost(), getPort());
} catch (Exception e) {
printDebug( "Failed to connect to " + host + ": "
+ e.toString() );
setErrorCode( CONNECT_ERROR );
notifyResult(null);
return false;
}
// Authenticate?
if ( (dn != null) && (password != null) &&
(dn.length() > 0) && (password.length() > 0) ) {
printDebug( "Authenticating " + dn + " - " + password );
try {
m_ldc.authenticate( dn, password );
} catch (Exception e) {
printDebug( "Failed to authenticate to " +
host + ": " + e.toString() );
setErrorCode( AUTHENTICATION_ERROR );
notifyResult(null);
return false;
}
}
int numDataEntries = 0;
// Search
try {
String[] attrs = new String[4];
attrs[0] = "member";
attrs[1] = "uniqueMember";
attrs[2] = "memberOfGroup";
attrs[3] = "memberurl";
LDAPSearchResults results =
m_ldc.search( group,
LDAPConnection.SCOPE_BASE,
"objectclass=*",
attrs, false);
// Should be only one result, at most
LDAPEntry entry = null;
LDAPEntry currEntry = null;
while ( results.hasMoreElements() ) {
try {
currEntry = (LDAPEntry)results.next();
if (numDataEntries == 0)
entry = currEntry;
if (++numDataEntries > 1) {
printDebug( "More than one entry found for " +
getFilter() );
setErrorCode( AMBIGUOUS_RESULTS );
break;
}
} catch (LDAPReferralException e) {
if (getDebug()) {
notifyResult("Referral URLs: ");
LDAPUrl refUrls[] = e.getURLs();
for (int i = 0; i < refUrls.length; i++)
notifyResult(refUrls[i].getUrl());
}
continue;
} catch (LDAPException e) {
if (getDebug())
notifyResult(e.toString());
continue;
}
}
if (numDataEntries == 1) {
printDebug( "... " + entry.getDN() );
String normMember = normalizeDN( member );
// Good - exactly one entry found; get the attributes
LDAPAttributeSet attrset = entry.getAttributeSet();
Enumeration attrsenum = attrset.getAttributes();
while ( attrsenum.hasMoreElements() && !isMember ) {
LDAPAttribute attr =
(LDAPAttribute)attrsenum.nextElement();
printDebug( attr.getName() + " = " );
boolean urlHandler =
attr.getName().equalsIgnoreCase("memberurl");
/* Get the values as strings.
The following code also handles dynamic
groups by calling URLMatch to see if an entry
DN is found via a URL search.
This is transparent to the caller of the bean.
*/
Enumeration valuesenum = attr.getStringValues();
if (valuesenum != null) {
while (valuesenum.hasMoreElements()) {
String val = (String)valuesenum.nextElement();
if (urlHandler) {
if ( URLMatch(m_ldc, val, normMember) ) {
isMember = true;
setErrorCode( OK );
break;
}
}
printDebug( "\t\t" + val );
String normFound = normalizeDN( val );
if ( normMember.equals( normFound ) ) {
isMember = true;
setErrorCode( OK );
break;
}
}
} else {
setErrorCode(PROPERTY_NOT_FOUND);
printDebug("Failed to do string conversion for "+
attr.getName());
}
}
if ( !isMember )
setErrorCode( PROPERTY_NOT_FOUND );
}
} catch (Exception e) {
printDebug( "Failed to search for " + group + ": "
+ e.toString() );
setErrorCode( NO_SUCH_OBJECT );
}
if (numDataEntries == 0) {
printDebug( "No entries found for " + group );
setErrorCode( NO_SUCH_OBJECT );
}
try {
if ( (m_ldc != null) && m_ldc.isConnected() )
m_ldc.disconnect();
} catch ( Exception e ) {
}
if (isMember)
notifyResult("Y");
else
notifyResult("N");
return isMember;
}
/**
* Checks if an entity (specified by distinguished name) is a
* member of a particular group (specified by distinguished name)
* @param host host string
* @param port port number
* @param dn fully qualified distinguished name to authenticate;
* can be null or ""
* @param password password for authenticating the dn; can be null
* or ""
* @param group distinguished name of the group
* @param member distinguished name of member to be checked
* @return true if the specified member belongs to the group
*/
public boolean isMember( String host, int port,
String dn, String password,
String group, String member ) {
setHost(host);
setPort(port);
setAuthDN(dn);
setAuthPassword(password);
setGroup(group);
setMember(member);
return isMember();
}
/**
* Checks if an entity (specified by distinguished name) is a
* member of a particular group (specified by distinguished name)
* @return true if the specified member belongs to the group
*/
public void isMember(ActionEvent e) {
isMember();
}
/**
* Returns the distinguished name of the group
* @return group name
*/
public String getGroup() {
return _group;
}
/**
* Sets the distinguished name of the group
* @param group group name
*/
public void setGroup( String group ) {
_group = group;
}
/**
* Returns the distinguished name of the member
* @return member name
*/
public String getMember() {
return _member;
}
/**
* Sets the distinguished name of the member
* @param member member name
*/
public void setMember( String member ) {
_member = member;
}
private String normalizeDN( String dn ) {
return new DN( dn ).toRFCString().toUpperCase();
}
/**
* Return true if normMember is result of url search.
* Urls from dynamic groups do not typically contain
* the host and port so we need to fix them before
* constructing an LDAP URL.
* current ldap:///.... make ldap://host:port/...
**/
private boolean URLMatch(LDAPConnection ld, String URL,
String normMemberDN) {
String cURL = URL;
boolean isMember = false;
int loc = URL.indexOf(":///");
if ( loc > 0) {
cURL = URL.substring(0,loc) + "://" + ld.getHost() +
":" + ld.getPort() + URL.substring(loc+3);
}
printDebug("URLMatch: url = " + cURL +
", member DN = " + normMemberDN);
LDAPUrl ldapurl;
try {
ldapurl = new LDAPUrl(cURL);
printDebug("URL ->"+ldapurl.getUrl());
} catch (java.net.MalformedURLException murl) {
printDebug("bad URL");
return isMember;
}
try {
LDAPSearchResults results = ld.search(ldapurl);
String entry = "";
while ( results.hasMoreElements() && !isMember ) {
try {
entry = ((LDAPEntry)results.next()).getDN();
String normEntry = normalizeDN( entry );
if (normEntry.equals(normMemberDN)) {
isMember = true;
break;
}
} catch (LDAPReferralException e) {
if (getDebug()) {
notifyResult("Referral URLs: ");
LDAPUrl refUrls[] = e.getURLs();
for (int i = 0; i < refUrls.length; i++)
notifyResult(refUrls[i].getUrl());
}
continue;
} catch (LDAPException e) {
if (getDebug())
notifyResult(e.toString());
continue;
}
}
} catch (LDAPException lde) {
printDebug("Failed search for url " + ldapurl.getUrl());
setErrorCode(NO_SUCH_OBJECT);
}
return isMember;
}
/**
* The main body if we run it as application instead of applet.
* @param args list of arguments
*/
public static void main(String args[]) {
if (args.length != 4) {
System.out.println( "Usage: LDAPIsMember host port group" +
" member" );
System.exit(1);
}
LDAPIsMember app = new LDAPIsMember();
app.setHost( args[0] );
app.setPort( java.lang.Integer.parseInt( args[1] ) );
app.setGroup( args[2] );
app.setMember( args[3] );
boolean response = app.isMember();
if ( response == false )
System.out.println( "Not a member" );
else
System.out.println( "Is a member" );
System.exit(0);
}
/*
* Variables
*/
public static final int OK = 0;
public static final int INVALID_PARAMETER = 1;
public static final int CONNECT_ERROR = 2;
public static final int AUTHENTICATION_ERROR = 3;
public static final int PROPERTY_NOT_FOUND = 4;
public static final int AMBIGUOUS_RESULTS = 5;
public static final int NO_SUCH_OBJECT = 5;
private String _group = new String("");
private String _member = new String("");
private String _result = new String("");
}

View File

@@ -0,0 +1,6 @@
Name: netscape/ldap/beans/LDAPIsMember.class
Java-Bean: True
Name: netscape/ldap/beans/LDAPBasePropertySupport.class
Name: netscape/ldap/beans/LDAPIsMemberBeanInfo.class

View File

@@ -0,0 +1,110 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap.beans;
import java.beans.SimpleBeanInfo;
import java.beans.BeanDescriptor;
import java.beans.EventSetDescriptor;
import java.beans.MethodDescriptor;
import java.beans.PropertyDescriptor;
import java.beans.ParameterDescriptor;
import java.beans.BeanInfo;
/**
* BeanInfo for LDAPIsMember
*/
public class LDAPIsMemberBeanInfo extends SimpleBeanInfo {
public LDAPIsMemberBeanInfo() throws Exception {
beanClass = Class.forName( "netscape.ldap.beans.LDAPIsMember" );
// Publish properties -------------------------------------------------
try {
PropertyDescriptor host =
new PropertyDescriptor("host", beanClass);
PropertyDescriptor port =
new PropertyDescriptor("port", beanClass);
PropertyDescriptor authDN =
new PropertyDescriptor("authDN", beanClass);
PropertyDescriptor authPassword =
new PropertyDescriptor("authPassword", beanClass);
PropertyDescriptor group =
new PropertyDescriptor("group", beanClass);
PropertyDescriptor member =
new PropertyDescriptor("member", beanClass);
PropertyDescriptor debug =
new PropertyDescriptor("debug", beanClass);
PropertyDescriptor rv[] =
{host, port, authDN, authPassword, group, member, debug};
_propertyDescriptor = new PropertyDescriptor[rv.length];
for( int i = 0; i < rv.length; i++ )
_propertyDescriptor[i] = rv[i];
} catch (Exception e) {
throw new Error(e.toString());
}
// Publish descriptor ---------------------------------------------
try {
_beanDescriptor = new BeanDescriptor(beanClass);
_beanDescriptor.setDisplayName( "LDAP IsMember" );
_beanDescriptor.setShortDescription(
"LDAP IsMember -"
+ " provided a host, port, group name and member name,"
+ " and optionally an authentication name and password,"
+ " return true if the member belongs to the group." );
} catch (Exception e) {
}
}
/**
* @return the public properties
*/
public PropertyDescriptor[] getPropertyDescriptors() {
return _propertyDescriptor;
}
public EventSetDescriptor[] getEventSetDescriptors() {
return _eventSetDescriptor;
}
public BeanInfo[] getAdditionalBeanInfo() {
return null;
}
public int getDefaultEventIndex() {
return -1;
}
public int getDefaultPropertyIndex() {
return -1;
}
public BeanDescriptor getBeanDescriptor() {
return _beanDescriptor;
}
private static Class beanClass;
private BeanDescriptor _beanDescriptor;
private EventSetDescriptor[] _eventSetDescriptor;
private PropertyDescriptor[] _propertyDescriptor;
}

View File

@@ -0,0 +1,178 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap.beans;
import netscape.ldap.*;
import netscape.ldap.beans.LDAPBasePropertySupport;
import java.io.Serializable;
import java.awt.event.*;
/**
* Invisible Bean that just authenticates a user with a Directory
* Server and returns Y or N. It takes a host and port, and then either
* a full distinguished name and password, an RDN and directory base, or
* a cn value and directory base.
* <BR><BR>
* Optionally, a client can register as
* a PropertyChangeListener and will be notified when an authentication
* completes.
* <BR><BR>
* The Bean can be used from JavaScript, as in the following example
* where the parameters are taken from HTML text fields in an HTML
* form called "input":
* <PRE>
* <XMP>
* <SCRIPT LANGUAGE="JavaScript">
* function checkAuthentication() {
* auth = new Packages.netscape.ldap.beans.LDAPSimpleAuth();
* auth.setHost( document.input.host.value );
* auth.setPort( parseInt(document.input.port.value) );
* auth.setAuthDN( document.input.username.value );
* auth.setAuthPassword( document.input.password.value );
* result = auth.authenticate();
* alert( "The response is: " + result );
* }
* </SCRIPT>
* </XMP>
*</PRE>
*/
public class LDAPSimpleAuth extends LDAPBasePropertySupport implements
Serializable {
/**
* Constructor with no parameters
*/
public LDAPSimpleAuth() {}
/**
* Constructor with host and port initializers
* @param theHost host string
* @param thePort port number
*/
public LDAPSimpleAuth( String theHost,
int thePort ) {
setHost( theHost );
setPort( thePort );
}
/**
* Constructor with all required authentication parameters
* @param theHost host string
* @param thePort port number
* @param dn fully qualified distinguished name to authenticate
* @param password password for authenticating the dn
*/
public LDAPSimpleAuth( String theHost,
int thePort,
String dn,
String password ) {
setHost( theHost );
setPort( thePort );
setAuthDN( dn );
setAuthPassword( password );
}
private void notifyResult( String newResult ) {
firePropertyChange( "result", result, newResult );
result = newResult;
}
/**
* Connect to LDAP server using parameters specified in
* constructor and/or by setting properties and attempt to
* authenticate.
* @return "Y" on successful authentication, "N" otherwise
*/
public String authenticate() {
LDAPConnection m_ldc = null;
String result = "N";
try {
m_ldc = new LDAPConnection();
System.out.println("Connecting to " + getHost() +
" " + getPort());
connect( m_ldc, getHost(), getPort());
} catch (Exception e) {
System.out.println( "Failed to connect to " + getHost() +
": " + e.toString() );
}
if ( m_ldc.isConnected() ) {
System.out.println( "Authenticating " + getAuthDN() );
try {
m_ldc.authenticate( getAuthDN(), getAuthPassword() );
result = "Y";
} catch (Exception e) {
System.out.println( "Failed to authenticate to " +
getHost() + ": " + e.toString() );
}
}
try {
if ( (m_ldc != null) && m_ldc.isConnected() )
m_ldc.disconnect();
} catch ( Exception e ) {
}
notifyResult( result );
return result;
}
/**
* Connect to LDAP server using parameters specified in
* constructor and/or by setting properties and attempt to
* authenticate.
* @param dn fully qualified distinguished name to authenticate
* @param password password for authenticating the dn
* @return "Y" on successful authentication, "N" otherwise
*/
public String authenticate( String dn,
String password ) {
setAuthDN( dn );
setAuthPassword( password );
return authenticate();
}
public void authenticate( ActionEvent x) {
authenticate();
}
/**
* The main body if we run it as stand-alone application.
* @param args list of arguments
*/
public static void main(String args[]) {
if (args.length != 4) {
System.out.println( " LDAPSimpleAuth " +
"host port DN password" );
System.exit(1);
}
LDAPSimpleAuth app = new LDAPSimpleAuth();
app.setHost( args[0] );
app.setPort( java.lang.Integer.parseInt( args[1] ) );
app.setAuthDN( args[2] );
app.setAuthPassword( args[3] );
String response = app.authenticate();
System.out.println( "Response: " + response );
System.exit(0);
}
/*
* Variables
*/
transient private String result = new String("");
}

View File

@@ -0,0 +1,6 @@
Name: netscape/ldap/beans/LDAPSimpleAuth.class
Java-Bean: True
Name: netscape/ldap/beans/LDAPBasePropertySupport.class
Name: netscape/ldap/beans/LDAPSimpleAuthBeanInfo.class

View File

@@ -0,0 +1,118 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap.beans;
import java.beans.SimpleBeanInfo;
import java.beans.BeanDescriptor;
import java.beans.EventSetDescriptor;
import java.beans.MethodDescriptor;
import java.beans.PropertyDescriptor;
import java.beans.ParameterDescriptor;
import java.beans.BeanInfo;
/**
* BeanInfo for LDAPSimpleAuth
*/
public class LDAPSimpleAuthBeanInfo extends SimpleBeanInfo {
public LDAPSimpleAuthBeanInfo() throws Exception {
beanClass = Class.forName( "netscape.ldap.beans.LDAPSimpleAuth" );
try {
PropertyDescriptor host =
new PropertyDescriptor("host", beanClass);
PropertyDescriptor port =
new PropertyDescriptor("port", beanClass);
PropertyDescriptor authDN =
new PropertyDescriptor("authDN", beanClass);
PropertyDescriptor authPassword =
new PropertyDescriptor("authPassword", beanClass);
PropertyDescriptor debug =
new PropertyDescriptor("debug", beanClass);
PropertyDescriptor rv[] =
{host, port, authDN, authPassword, debug};
_propertyDescriptor = new PropertyDescriptor[rv.length];
for( int i = 0; i < rv.length; i++ )
_propertyDescriptor[i] = rv[i];
} catch (Exception e) {
throw new Error(e.toString());
}
// Publish events --------------------------------------------------
try {
_eventSetDescriptor = new EventSetDescriptor[1];
_eventSetDescriptor[0] = new EventSetDescriptor(beanClass,
"propertyChange",
Class.forName("java.beans.PropertyChangeListener"),
"propertyChange");
} catch (Exception e) {
throw new Error(e.toString());
}
// Publish descriptor ---------------------------------------------
try {
_beanDescriptor = new BeanDescriptor(beanClass);
_beanDescriptor.setDisplayName( "LDAP user authentication" );
_beanDescriptor.setShortDescription(
"LDAP user authentication -"
+ " provided a host, port, base, username, and password,"
+ " report if the user can be authenticated both as a"
+ " function return and as a Property change event." );
} catch (Exception e) {
}
}
/**
* @return the public properties
*/
public PropertyDescriptor[] getPropertyDescriptors() {
return _propertyDescriptor;
}
public EventSetDescriptor[] getEventSetDescriptors() {
return _eventSetDescriptor;
}
public BeanInfo[] getAdditionalBeanInfo() {
return null;
}
public int getDefaultEventIndex() {
return -1;
}
public int getDefaultPropertyIndex() {
return -1;
}
public BeanDescriptor getBeanDescriptor() {
return _beanDescriptor;
}
private static Class beanClass;
private BeanDescriptor _beanDescriptor;
private EventSetDescriptor[] _eventSetDescriptor;
private PropertyDescriptor[] _propertyDescriptor;
}

View File

@@ -0,0 +1,83 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap.util;
/**
* The exception thrown when there is a problem with either an LDAPFilter
* or with the File/URL/Buffer form which we're creating the LDAPFilter.
*
* @see LDAPFilter
* @see LDAPFilterDescriptor
* @version 1.0
*/
public class BadFilterException extends Exception {
private String m_strException;
private int m_nLine = -1;
/**
* Creates an <b>Unknown</b> BadFilterException
*/
public BadFilterException () {
m_strException = "Unknown Error";
}
/**
* Creates a BadFilterException with the
* given string
*/
public BadFilterException ( String s ) {
m_strException = s;
}
/**
* Creates a BadFilterException with the
* given string and line number
*/
public BadFilterException ( String s, int nErrorLineNumber ) {
m_strException = s;
m_nLine = nErrorLineNumber;
}
/**
* Returns the exception string.
*/
public String toString() {
return m_strException;
}
/**
* If appropriate, return the line number of the ldapfilter.conf
* file (or url or buffer) where this error occurred. This method
* will return -1 if the line number was not set.
*/
public int getErrorLineNumber() {
return m_nLine;
}
/**
* Set the line number in the ldapfilter.conf file/url/buffer where
* this error occurred.
*/
void setErrorLineNumber ( int nErrorLineNumber ) {
m_nLine = m_nLine;
}
}

View File

@@ -0,0 +1,529 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap.util;
import netscape.ldap.*;
import java.util.*;
/**
* Represents an LDAP search filter, which includes the string-based
* representation of the filter and other information retrieved from the
* LDAP filter configuration file (or from a buffer in memory or from a URL).
* <P>
*
* Although this class provides methods to create and modify LDAP
* filters, in most cases, you do not need to use these methods.
* In most situations, these classes are used to access individual
* filters from filter configuration files.
* <P>
*
* For example, you might do the following:
* <P>
*
* <OL>
* <LI>Connect to the LDAP server and accept a set of search criteria.
* <LI>Create an LDAP filter configuration file.
* <LI>Call the <CODE>LDAPFilterDescriptor</CODE> constructor to
* read the filter configuration file into memory.
* <LI>Call the <CODE>getFilters</CODE> method to get a list of
* filters that match the search criteria. This list of filters
* is represented by an <CODE>LDAPFilterList</CODE> object.
* <LI>Iterate through the list of filters (each filter is represented
* by an <CODE>LDAPFilter</CODE> object), and apply the filter to
* a search.
* </OL>
* <P>
*
* For an example of using an object of this class and for more information on
* the filter configuration file syntax, see the documentation for <a
* href="n.l.u.LDAPFilterDescriptor.html">LDAPFilterDescriptor</a>.
* <P>
*
* @see LDAPFilterDescriptor
* @see LDAPFilterList
* @version 1.0
*/
public class LDAPFilter implements Cloneable {
private static final int DEFAULT_FILTER_LENGTH = 256;
private String m_strFilter = null;
private String m_strDescription; // token 4 from filter configuration file
private int m_nScope; // token 5 from filter configuration file
private boolean m_bIsExact;
private String m_strMatchPattern; // token 1 from filter configuration file
private String m_strDelimeter; // token 2 from filter configuration file
private String m_strFilterTemplate; // token 3 from filter configuration file
private int m_nLine;
private String m_strSuffix;
private String m_strPrefix;
/**
* Constructs an <CODE>LDAPFilter</CODE> object. In most situations,
* you do not need to construct an LDAPFilter object. Instead, you
* work with <CODE>LDAPFilter</CODE> objects created from the
* <CODE>LDAPFilter</CODE> objects and <CODE>LDAPFilterDescriptor</CODE>
* objects.
* <P>
*
* This constructor uses the integer value for a search scope in
* addition to other information to construct an <CODE>LDAPFilter</CODE>
* object. The integer value of the search scope can be one of the
* following:
* <ul>
* <li><CODE>LDAPConnection.SCOPE_BASE</CODE>
* <li><CODE>LDAPConnection.SCOPE_ONE</CODE>
* <li><CODE>LDAPConnection.SCOPE_SUB</CODE>
* </ul>
*
* If an invalid scope is specified, the constructor throws an
* <CODE>illegalArgumentException</CODE>.
*/
public LDAPFilter ( String strMatchPattern,
String strDelimeter,
String strFilterTemplate,
String strDescription,
int nScope ) throws IllegalArgumentException{
m_strMatchPattern = convertMatchPattern ( strMatchPattern );
m_strDelimeter = strDelimeter;
m_strFilterTemplate = strFilterTemplate;
m_strDescription = strDescription;
m_nScope = nScope;
}
/**
* Constructs an <CODE>LDAPFilter</CODE> object. In most situations,
* you do not need to construct an LDAPFilter object. Instead, you
* work with <CODE>LDAPFilter</CODE> objects created from the
* <CODE>LDAPFilter</CODE> objects and <CODE>LDAPFilterDescriptor</CODE>
* objects.
* <P>
*
* This constructor uses the string value for a search scope in
* addition to other information to construct an <CODE>LDAPFilter</CODE>
* object. The string value of the search scope can be one of the
* following:
* <ul>
* <li><CODE>&quot;base&quot;</CODE>
* <li><CODE>&quot;onelevel&quot;</CODE>
* <li><CODE>&quot;subtree&quot;</CODE>
* </ul>
*
* If an invalid scope is specified, the constructor throws an
* <CODE>illegalArgumentException</CODE>.
*/
public LDAPFilter ( String strMatchPattern,
String strDelimeter,
String strFilterTemplate,
String strDescription,
String strScope )
throws IllegalArgumentException {
if ( strScope.equals ( "base" ) ) {
m_nScope = LDAPConnection.SCOPE_BASE;
} else if ( strScope.equals ( "onelevel" ) ) {
m_nScope = LDAPConnection.SCOPE_ONE;
} else if ( strScope.equals ( "subtree" ) ) {
m_nScope = LDAPConnection.SCOPE_SUB;
}
m_strMatchPattern = strMatchPattern;
m_strDelimeter = strDelimeter;
m_strFilterTemplate = strFilterTemplate;
m_strDescription = strDescription;
}
/**
* Print out a string representation of the LDAPFilter.
* Basically, it prints out the appropriate fields.
* <P>
*
* For example, suppose you called the method in this way:
* <P>
*
* <PRE>System.out.println(filter.toString());</PRE>
*
* The resulting output might look like this:
* <P>
*
* <PRE>
* matchPtn: "@"
* delim: " "
* filttmpl: "(mail=%v*)"
* descript: "start of email address"
* scope: "LDAPConnection.SCOPE_SUB"
* line: "32"
* FILTER: "(mail=babs@aceindustry.com*)"
* </PRE>
*/
public String toString() {
StringBuffer strBuf = new StringBuffer ( 300 );
strBuf.append ( " matchPtn: \"" + m_strMatchPattern+"\"\n" );
strBuf.append ( " delim: \"" + m_strDelimeter+"\"\n" );
strBuf.append ( " filttmpl: \"" + m_strFilterTemplate+"\"\n" );
strBuf.append ( " descript: \"" + m_strDescription+"\"\n" );
switch ( m_nScope ) {
case LDAPConnection.SCOPE_BASE:
strBuf.append ( " scope: \"LDAPConnection.SCOPE_BASE\"\n" );
break;
case LDAPConnection.SCOPE_ONE:
strBuf.append ( " scope: \"LDAPConnection.SCOPE_ONE\"\n" );
break;
case LDAPConnection.SCOPE_SUB:
strBuf.append ( " scope: \"LDAPConnection.SCOPE_SUB\"\n" );
break;
}
strBuf.append ( " line: \"" + m_nLine+"\"\n" );
strBuf.append ( " FILTER: \"" + m_strFilter+"\"\n" );
return strBuf.toString();
}
/**
* Sets up the filter string, given the string <CODE>strValue</CODE>.
* If the <CODE>strPrefix</CODE> and <CODE>strSuffix</CODE> arguments
* are non-null strings, they are prepended and appended
* to the filter string (respectively).
* <P>
*
* This string, which is available through the <CODE>getFilter()</CODE>
* method, should be suitable for use as search criteria when
* calling the <CODE>LDAPConnection.search()</CODE> method.
* <P>
*
* <b>Notes:</b>
* <P>
*
* <UL>
* <LI>This method <i>does not</i> maintain the affixes
* set with the <CODE>LDAPFilterDescriptor.setFilterAffixes</CODE>
* method, so you
* need to explicitly define any filter prefixes or suffixes here.<p>
*
* <LI> This method only uses the
* strPrefix and strSuffix for this invocation of setupFilter. It
* does not redefine strPrefix and strSuffix for later
* invocations. <p>
* </UL>
* <P>
*
* @see netscape.ldap.util.LDAPFilterDescriptor#setFilterAffixes
* @see #setFilterAffixes
*/
public void setupFilter ( String strValue, String strPrefix,
String strSuffix ) {
createFilterString ( strValue, strPrefix, strSuffix );
}
/**
* Sets up the filter string, given the string <CODE>strValue</CODE>.
* This string, which is available through the <CODE>getFilter()</CODE>
* method, should be suitable for use as search criteria when
* calling the <CODE>LDAPConnection.search()</CODE> method.
* <P>
*
* <b>Note:</b> If you want to specify a filter prefix and suffix,
* you need to explicitly define them by calling the
* <CODE>setFilterAffixes()</CODE> method.
*
* @see netscape.ldap.util.LDAPFilterDescriptor#setFilterAffixes
* @see #setFilterAffixes
*
*/
public void setupFilter ( String strValue ) {
createFilterString ( strValue, null, null );
}
/**
* Create the filter string which can be used in
* LDAPConnection.search() and others given the parameter
* strValue. If strPrefix and strSuffix are non-null strings,
* prepend strPrefix and append strSuffix.
*/
void createFilterString ( String strValue, String strPrefix,
String strSuffix ) {
StringTokenizer strTok =
new StringTokenizer ( strValue, m_strDelimeter );
// Initialize an array of broken up values so that we
// can reference them directly.
String[] aValues = new String[strTok.countTokens()];
int nTokens = strTok.countTokens();
for ( int i = 0; i < nTokens; i++ ) {
aValues[i] = strTok.nextToken();
}
StringBuffer sbFilter = new StringBuffer ( DEFAULT_FILTER_LENGTH);
if ( strPrefix != null ) {
sbFilter.append ( strPrefix );
}
char[] cFilterTemplate = m_strFilterTemplate.toCharArray();
int i = 0;
while ( i < cFilterTemplate.length ) {
if ( cFilterTemplate[i] == '%' ) {
i++;
if ( cFilterTemplate[i] == 'v' ) {
if ( i == (cFilterTemplate.length-1) ) {
sbFilter.append ( strValue );
break;
}
i++;
switch ( cFilterTemplate[i] ) {
case '$':
sbFilter.append ( aValues[aValues.length] );
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
int nValue = Integer.parseInt
( new Character
(cFilterTemplate[i]).toString() );
nValue--;
i++;
if ( cFilterTemplate[i] == '-' ) {
i++;
if ( Character.isDigit ( cFilterTemplate[i] )) {
int nValue2 = Integer.parseInt
( new Character
(cFilterTemplate[i]).toString() );
nValue2--;
for ( int j = nValue; j <= nValue2; j++ ) {
sbFilter.append ( aValues[j] );
sbFilter.append
( ( j == nValue2 ) ? "" : " " );
}
} else {
for ( int j = nValue; j < aValues.length;j++ ) {
sbFilter.append ( aValues[j] );
sbFilter.append
( ( j == aValues.length - 1 ) ? "" : " " );
}
sbFilter.append ( cFilterTemplate[i]);
}
} else {
sbFilter.append ( aValues[nValue] );
sbFilter.append ( cFilterTemplate[i] );
}
break;
// We just got a plain old %v, so insert the
// strValue
default:
sbFilter.append ( strValue );
sbFilter.append ( cFilterTemplate[i] );
break;
}
} else {
sbFilter.append ( "%" );
sbFilter.append ( cFilterTemplate[i] );
}
} else {
sbFilter.append ( cFilterTemplate[i] );
}
i++;
}
if ( strSuffix != null ) {
sbFilter.append ( strSuffix );
}
m_strFilter = sbFilter.toString();
}
/**
* Makes a copy of this <CODE>LDAPFilter</CODE> object.
*/
public Object clone() {
try {
return super.clone();
} catch ( CloneNotSupportedException e ) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
/**
* Set the line number from which this filter was created. This
* is used only when the LDAPFilter is created when an
* LDAPFilterDescriptor is initialized from a file/URL/buffer.
*/
void setLine ( int nLine ) {
m_nLine = nLine;
}
/**
* The ldapfilter.conf specifies match patterns in a funny way.
* A "." means "any character" except when used inside of a set of
* square brackets "[]", in which case, the "." means just a
* plain old period (not a * special character).
*
* This function converts periods inside of a set of square
* brackets into a "\." as per normal regexp code.
*/
String convertMatchPattern ( String strMatchPattern ) {
StringBuffer sb = new StringBuffer ( strMatchPattern.length() + 1);
char[] a_cMatchPattern = strMatchPattern.toCharArray();
boolean bInBrackets = false;
for ( int i = 0; i < a_cMatchPattern.length; i++ ) {
if ( a_cMatchPattern[i] == '.' ) {
if ( bInBrackets ) {
sb.append ( "\\" );
}
} else if ( a_cMatchPattern[i] == '[' ) {
bInBrackets = true;
} else if ( a_cMatchPattern[i] == ']' ) {
bInBrackets = false;
}
sb.append ( a_cMatchPattern[i] );
}
return sb.toString();
}
/**
* Returns the filter string. This method will return null if the
* filter string has not been calculated by the <CODE>setupFilter()</CODE>,
* <CODE>getFilter (strValue)</CODE>, or <CODE>getFilter (strValue,
* strPrefix, strSuffix )</CODE> methods.
*
* @see #setupFilter
* @see #getFilter
*/
public String getFilter () {
return m_strFilter;
}
/**
* Create a filter string given a string value. This method uses
* any Prefixes or Suffixes that have been set by the
* setFilterAffixes() method.<p>
*
* This is the same as doing:
* <pre>
* setupFilter ( strValue );
* getFilter();
* </pre>
*/
public String getFilter ( String strValue ) {
createFilterString ( strValue, m_strPrefix, m_strSuffix );
return m_strFilter;
}
/**
* Create a filter string given a string value. If strPrefix
* and/or strSuffix is non-null, these values are prepended and
* appended to the returned string.<p>
*
* This is the same as doing:
* <pre>
* setupFilter ( strValue, strPrefix, strSuffix );
* getFilter();
* </pre>
*/
public String getFilter ( String strValue, String strPrefix,
String strSuffix ) {
createFilterString ( strValue, strPrefix, strSuffix );
return m_strFilter;
}
/**
* Return this filter's match pattern. The match pattern is
* found as the first token in a filter configuration line in the
* ldapfilter.conf file.
*/
public String getMatchPattern() {
return m_strMatchPattern;
}
/**
* Return this filter's delimeter. The delmimeter is
* found as the second token in a filter configuration line in the
* ldapfilter.conf file.
*/
public String getDelimeter() {
return m_strDelimeter;
}
/**
* Return this filter's filter template. The filter template is
* found as the third token in a filter configuration line in the
* ldapfilter.conf file.
*/
public String getFilterTemplate() {
return m_strFilterTemplate;
}
/**
* Return this filter's description. The description is
* found as the fourth token in a filter configuration line in the
* ldapfilter.conf file.
*/
public String getDescription() {
return m_strDescription;
}
/**
* Return this filter's scope. The scope is
* found as the fifth (optional) token in a filter configuration
* line in the ldapfilter.conf file.
*/
public String getScope() {
switch ( m_nScope ) {
case LDAPConnection.SCOPE_BASE:
return "base";
case LDAPConnection.SCOPE_ONE:
return "onelevel";
case LDAPConnection.SCOPE_SUB:
return "subtree";
default:
return "UNKNOWN!";
}
}
/**
* Return this filter's line number. The line number is
* mostly a debugging variable to let the developer know which
* filter from the filter configuration file is being used.
*/
public String getLineNumber() {
return Integer.toString ( m_nLine );
}
public void setFilterAffixes ( String strPrefix, String strSuffix ) {
m_strPrefix = strPrefix;
m_strSuffix = strSuffix;
}
}

View File

@@ -0,0 +1,492 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap.util;
import java.io.*;
import java.util.*;
import java.net.*;
import com.oroinc.text.regex.*;
import netscape.ldap.*;
/**
* Represents an LDAP filter configuration file read into memory.
* <P>
*
* Once you read in a filter file to create an object of this class,
* you can access the filter information through the methods that create
* <CODE>LDAPFilterList</CODE> and <CODE>LDAPFilter</CODE> objects.
* (You do not need to manually construct these objects yourself.)
* <P>
*
* This class (along with the other LDAP filter classes) provide
* functionality equivalent to the LDAP filter functions in the LDAP C API.
* <p>
*
* The format of the file/URL/buffer must be that as defined in the
* ldapfilter.conf(5) man page from the University of Michigan LDAP-3.3
* distribution. <p>
*
* The LDAP filter classes provide a powerful way to configure LDAP clients
* by modifying a configuration file.<p>
*
* The following is a short example for how to use the
* LDAP filter classes.
*
* <pre>
*
* // ... Setup LDAPConnection up here ...
* <p>
*
* LDAPFilterDescriptor filterDescriptor;
* <p>
*
* // Create the LDAPFilterDescriptor given the file
* // "ldapfilter.conf".
* try {
* filterDescriptor = new LDAPFilterDescriptor ( "ldapfilter.conf" );
* <p>
*
* // Now retrieve the Filters in the form of an
* // LDAPFilterList
* LDAPFilterList filterList = new filterDescriptor.getFilters("match_tag", "string_user_typed");
* <p>
*
* // For each filter, do the search. Normally, you wouldn't
* // do the search if the first filter matched, but this is
* // just showing the enumeration type aspects of
* // LDAPFilterList
* LDAPFilter filter;
* while ( filterList.hasMoreElements() ) {
* filter = filterList.next();
* LDAPResults results = LDAPConnection.search (
* strBase, // base DN
* filter.getScope(), // scope
* filter.getFilter(), // completed filter
* null, // all attribs
* false ); // attrsOnly?
* }
* <p>
*
* // ...more processing here...
* } catch ( BadFilterException e ) {
* System.out.println ( e.toString() );
* System.exit ( 0 );
* } catch ( IOException e ) {
* // ...handle exception here...
* }
* </pre>
*
*
* @see LDAPFilterList
* @see LDAPFilter
* @version 1.0
*/
public class LDAPFilterDescriptor {
private Vector m_vFilterSet = new Vector();
private String m_strLine;
private int m_nLine;
private String m_strPrefix;
private String m_strAffix;
private LDAPIntFilterSet m_tmpFilterSet = null;
private String m_strLastMatchPattern = null;
private String m_strLastDelimiter = null;
/**
* The Default scope is used when a scope is not defined
* in the filter file. The scope is the only "optional" parameter
* in the file.
*/
private static final int DEFAULT_SCOPE = LDAPConnection.SCOPE_SUB;
/**
* Creates an LDAPFilterDescriptor object from an existing filter
* configuration file. This file has the format as defined in the
* ldapfilter.conf(5) man page.
*
* @exception netscape.ldap.util.BadFilterException
* One of the filters was not generated properly. Most likely
* this is due to an improperly formatted ldapfilter.conf file.
*/
public LDAPFilterDescriptor ( String strFile )
throws FileNotFoundException, BadFilterException {
DataInputStream inputStream =
new DataInputStream ( new FileInputStream ( strFile ) );
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
init( reader );
}
/**
* Creates an LDAPFilterDescriptor object from an existing
* StringBuffer. This file has the format as defined in the
* ldapfilter.conf(5) man page.
*
* @exception netscape.ldap.util.BadFilterException
* One of the filters was not generated properly. Most likely
* this is due to an improperly formatted ldapfilter.conf file.
*/
public LDAPFilterDescriptor ( StringBuffer strBuffer )
throws BadFilterException {
init( strBuffer );
}
/**
* Creates an LDAPFilterDescriptor object from a URL.
* This file has the format as defined in the
* ldapfilter.conf(5) man page.
*
* @exception netscape.ldap.util.BadFilterException
* One of the filters was not generated properly. Most likely
* this is due to an improperly formatted ldapfilter.conf file.
*/
public LDAPFilterDescriptor ( URL url )
throws IOException, BadFilterException {
URLConnection urlc = url.openConnection();
DataInputStream inputStream =
new DataInputStream ( urlc.getInputStream() );
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
init( reader );
}
/**
* This function initializes the LDAPFilterDescriptor. It's
* called internally, and should never be called directly by the
* developer.
*/
private void init ( Object inputObj)
throws BadFilterException {
String strCommentPattern = "(?:^\\s*#|^\\s*$)";
String strDataPattern = "(?:\\s*\"([^\"]*)\"|([^\\s]*))\\s*";
Perl5Compiler compiler = new Perl5Compiler();
Perl5Pattern patComment;
Perl5Pattern patData;
Vector vStrings = new Vector ( 5 );
try {
patComment = (Perl5Pattern)compiler.compile ( strCommentPattern );
patData = (Perl5Pattern)compiler.compile ( strDataPattern );
} catch ( MalformedPatternException e ) {
// This should NEVER happen...
System.out.println ( "FATAL Error, couldn't compile pattern");
System.out.println ( " " + e.getMessage() );
return;
}
// Setup some temporary variables.
m_nLine = 0;
try {
if (inputObj instanceof StringBuffer) {
StringBuffer ibuffer = (StringBuffer)inputObj;
StringBuffer buffer = new StringBuffer();
for (int i=0; i<ibuffer.length(); i++) {
if (ibuffer.charAt(i) == '\n') {
m_strLine = buffer.toString();
m_nLine++;
setFilter(patComment, patData, vStrings);
buffer = new StringBuffer();
} else
buffer.append(ibuffer.charAt(i));
}
} else {
while ((m_strLine=((BufferedReader)inputObj).readLine()) != null) {
m_nLine++;
setFilter(patComment, patData, vStrings);
}
}
// BUGBUG: Fixed. 7-28-97
// We're done with the input, so we need to append the
// last temporary FilterSet into the list of FilterSets.
if ( m_tmpFilterSet != null ) {
m_vFilterSet.addElement ( m_tmpFilterSet );
}
} catch ( IOException e ) {
}
}
private void setFilter(Perl5Pattern patComment, Perl5Pattern patData,
Vector vStrings) throws IOException, BadFilterException {
MatchResult result;
Perl5Matcher matcher = new Perl5Matcher();
PatternMatcherInput input;
LDAPFilter tmpFilter = null;
input = new PatternMatcherInput ( m_strLine );
if ( ! ( matcher.contains ( input, patComment ) ) ) {
input.setCurrentOffset(input.getBeginOffset());
// System.out.println ( "\nNEW LINE: " + m_strLine );
if ( ! vStrings.isEmpty() ) {
vStrings.removeAllElements();
}
while ( matcher.contains ( input, patData ) ) {
// Within this while loop, we're looking for
// all the data tokens. Our regular
// expression is setup to look for words
// separated by whitespace or sets of
// characters in quotataion marks. A remnant
// of the regexp is that we have two
// backreferences, only one will have data at
// any time.
result = matcher.getMatch();
for ( int i = 1; i <=2; i++ ) {
if ( result.group(i) != null ) {
if ( ! result.group(i).equals ( "" ) ) {
//System.out.println ( "Match #" + i +
// ": \"" + result.group(i) + "\"" );
vStrings.addElement ( result.group(i));
}
}
}
}
switch ( vStrings.size() ) {
case 1:
// If the current filter set is not null,
// add it to the filter set vector.
if ( m_tmpFilterSet != null ) {
m_vFilterSet.addElement ( m_tmpFilterSet );
}
// Now create a new filterset.
m_tmpFilterSet = new LDAPIntFilterSet
( (String)vStrings.elementAt ( 0 ) );
break;
// Two tokens mens we're the the second (or
// higher line in a token. We need to append
// the information stored in the list onto
// the tmpFilter.
case 2:
if ( ( m_strLastMatchPattern != null ) &&
( m_strLastDelimiter != null ) ) {
tmpFilter = new LDAPFilter(
m_strLastMatchPattern,
m_strLastDelimiter,
(String)vStrings.elementAt ( 0 ),
(String)vStrings.elementAt ( 1 ),
DEFAULT_SCOPE );
tmpFilter.setLine ( m_nLine );
if ( m_tmpFilterSet != null ) {
m_tmpFilterSet.appendFilter ( tmpFilter );
} else {
throw MakeException ( "Attempting to add a filter to a null filterset" );
}
} else {
throw MakeException ( "Attempting to create a relative filter with no preceeding full filter" );
}
break;
// Three tokens means we're the second (or
// higher line in a filter. create a new
// filter grabbing info from the last filter
case 3:
if ( ( m_strLastMatchPattern != null ) &&
( m_strLastDelimiter != null ) ) {
tmpFilter = new LDAPFilter (
m_strLastMatchPattern,
m_strLastDelimiter,
(String)vStrings.elementAt ( 0 ),
(String)vStrings.elementAt ( 1 ),
(String)vStrings.elementAt ( 2 ) );
tmpFilter.setLine ( m_nLine );
if ( m_tmpFilterSet != null ) {
m_tmpFilterSet.appendFilter ( tmpFilter );
} else {
throw MakeException
("Attempting to add a filter to a null filterset");
}
} else {
throw MakeException
("Attempting to create a relative filter with no preceeding full filter" );
}
break;
// 4 tokens means this is the first line in a
// token. All data is new. However, we're using
// the default scope.
case 4:
tmpFilter = new LDAPFilter (
(String)vStrings.elementAt ( 0 ),
(String)vStrings.elementAt ( 1 ),
(String)vStrings.elementAt ( 2 ),
(String)vStrings.elementAt ( 3 ),
DEFAULT_SCOPE );
tmpFilter.setLine ( m_nLine );
m_strLastMatchPattern = (String)vStrings.elementAt ( 0 );
m_strLastDelimiter = (String)vStrings.elementAt ( 1 );
if ( m_tmpFilterSet != null ) {
m_tmpFilterSet.newFilter ( tmpFilter );
} else {
throw MakeException
("Attempting to add a filter to a null filterset");
}
break;
// 5 tokens means this is the first line in a
// token. All data is new.
case 5:
tmpFilter = new LDAPFilter (
(String)vStrings.elementAt ( 0 ),
(String)vStrings.elementAt ( 1 ),
(String)vStrings.elementAt ( 2 ),
(String)vStrings.elementAt ( 3 ),
(String)vStrings.elementAt ( 4 ) );
tmpFilter.setLine ( m_nLine );
m_strLastMatchPattern = (String)vStrings.elementAt ( 0 );
m_strLastDelimiter = (String)vStrings.elementAt ( 1 );
if ( m_tmpFilterSet != null ) {
m_tmpFilterSet.newFilter ( tmpFilter );
} else {
throw MakeException
("Attempting to add a filter to a null filterset");
}
break;
default:
throw MakeException ( "Wrong number of tokens (" + vStrings.size() + ")" );
//break;
}
}
}
/**
* just a utility method to create an exception.
*/
private BadFilterException MakeException ( String strMsg ) {
return new BadFilterException
( "BadFilterException while creating Filters,\n" +
"Line Number: " + m_nLine +
",\n --> " + m_strLine + "\nThe error is: " +
strMsg, m_nLine );
}
/**
* Output a text dump of this filter descriptor. It cycles
* through all of the internal LDAPIntFilterSet objects and calls
* their toString() methods.
*
* @see LDAPIntFilterSet#toString
*/
public String toString() {
StringBuffer strBuf = new StringBuffer ( 4000 );
for ( int i = 0; i < m_vFilterSet.size(); i++ ) {
strBuf.append ( "Filter Set number: " + i + "\n" );
strBuf.append (
((LDAPIntFilterSet)m_vFilterSet.elementAt ( i )).toString() +
"\n" );
strBuf.append ( "\n" );
//System.out.println ( (m_vFilterSet.elementAt ( i )).toString());
}
return strBuf.toString();
}
/**
* Return all the filters which match the strTagPat (regular
* expression), and the user input (strValue)
*/
public LDAPFilterList getFilters ( String strTagPat, String strValue )
throws IllegalArgumentException {
strTagPat = strTagPat.trim();
strValue = strValue.trim();
if ( ( strTagPat == null ) || ( strTagPat.equals ("") ) ) {
throw new IllegalArgumentException
( "The Tag Pattern can not be null" );
}
if ( ( strValue == null ) || ( strValue.equals ("") ) ) {
throw new IllegalArgumentException ( "The Value can not be null" );
}
LDAPFilterList retList = new LDAPFilterList();
Perl5Compiler compiler = new Perl5Compiler();
Perl5Pattern patTag; // The strTagPat that's compiled
// For efficiency, we're pre-allocating a patternMatcherInput
// here.
PatternMatcherInput matcherValue = new PatternMatcherInput ( strValue );
// first we need to make a new regexp from the strTagPat
// For efficiency, we're precompiling the strTagPat into
// a pattern here. That pattern doesn't change, the Tag string
// changes per LDAPFIlterSet.
try {
patTag = (Perl5Pattern)compiler.compile ( strTagPat );
} catch ( MalformedPatternException e ) {
throw new IllegalArgumentException
( "The parameter: " + strTagPat + " is not valid" );
}
// We "ask" each of the filterset's to see if there is
// a matching filter.
boolean bMatched = false;
int i = 0;
while ( ! bMatched ) {
Vector vMatchingFilters =
((LDAPIntFilterSet)m_vFilterSet.elementAt ( i )).getFilters
(patTag, matcherValue );
if ( vMatchingFilters.size() > 0 ) {
for ( int j = 0; j < vMatchingFilters.size(); j++ ) {
LDAPFilter tmpFilter =
(LDAPFilter)
((LDAPFilter)
vMatchingFilters.elementAt ( j )).clone();
tmpFilter.setupFilter ( strValue, m_strPrefix,
m_strAffix );
bMatched = true; // this really doesn't matter.
retList.add ( tmpFilter );
}
return retList;
}
i++;
}
return null;
}
/**
* Prepend the parameter (strPrefix) and append the second
* parameter (strAffix) to every filter that is returned by the
* getFilters() method. <p>
*/
public void setFilterAffixes ( String strPrefix, String strAffix ) {
m_strPrefix = strPrefix;
m_strAffix = strAffix;
}
}

View File

@@ -0,0 +1,97 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap.util;
import java.util.*;
/**
* The list of LDAPFilter objects returned from a LDAPFilterDescriptor
* Object. Note that this is an enumeration, so if multiple iterations
* are needed, save the results.
*
* @see LDAPFilterDescriptor
* @see LDAPFilter
* @version 1.0
*/
public class LDAPFilterList implements Enumeration {
private Vector m_vFilterList;
private static int DEFAULT_LIST_SIZE = 2;
/**
* Constructs an LDAPFilterList object. This methos shouldn't need to
* be called by the developer directly. Construction of the
* LDAPFilterList object should take place when the Prepare function
* of LDAPFilterDescriptor is called.
*
*/
public LDAPFilterList () {
m_vFilterList = new Vector ( DEFAULT_LIST_SIZE );
}
/**
* Add an LDAPFilter to the private vector. Since the filter we're
* being passed has already been cloned from the master
* LDAPFilterDescriptor set, all we have to do is add it to the list.
*/
void add ( LDAPFilter filter ) {
m_vFilterList.addElement ( filter );
}
/**
* Returns true if there are any LDAPFilter objects to returned.
*/
public boolean hasMoreElements() {
return ( ! m_vFilterList.isEmpty() );
}
/**
* Returns the next LDAPFilter as an Object. Note: the preferred way
* to return the next LDAPFilter is to call next()
*
* @see LDAPFilterList#next()
* @return The next LDAPFilter object (as an instance of Object)
*/
public Object nextElement() {
Object o = m_vFilterList.firstElement();
m_vFilterList.removeElementAt ( 0 );
return o;
}
/**
* Returns the next LDAPFilter
*
* @return The next LDAPFilter
*/
public LDAPFilter next() {
Object o = m_vFilterList.firstElement();
m_vFilterList.removeElementAt ( 0 );
return (LDAPFilter)o;
}
/**
* Return the number of filters in the filter list.
* Note that this number decreases every time next() or nextElement() is
* called because the elements are removed as they're returned.
*/
public int numFilters (){
return m_vFilterList.size();
}
}

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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap.util;
import java.util.*;
import com.oroinc.text.regex.*;
/**
* Represents an Internal LDAPFilterList object. This is an internal object
* that should never be instantiated directly by the developer. We
* store all filters that have the same match pattern here.
*/
public class LDAPIntFilterList {
private Vector m_vFilter;
private String m_strMatchPattern;
// a regexp pattern of m_strMatchPattern
private Perl5Pattern m_patMatch = null;
private Perl5Matcher m_matcher;
private Perl5Compiler m_compiler;
LDAPIntFilterList ( LDAPFilter filter ) throws
BadFilterException {
m_strMatchPattern = filter.getMatchPattern();
// We're going to compile the pattern for strMatchPattern
// now, so that we can throw an exception if it is a bad
// pattern.
m_matcher = new Perl5Matcher();
m_compiler = new Perl5Compiler();
try {
m_patMatch = (Perl5Pattern)m_compiler.compile
( m_strMatchPattern );
} catch ( MalformedPatternException e ) {
throw new BadFilterException (
"The Regular Expression for this filter is bad. " +
"Line number: " + filter.getLineNumber() );
}
m_vFilter = new Vector();
m_vFilter.addElement ( filter );
}
/**
* Add a "relative" filter to an existing filter list. We do this
* becuse the ldapfilter file defines that we can have multiple
* filters per match pattern (and delimeter). This method is
* called by the parent LDAPIntFilterSet because the file specified
* a "relative" filter (a filter in the ldapfilter.conf file that
* only has 2 or 3 tokens).
*/
void AddFilter ( LDAPFilter filter ) {
m_vFilter.addElement ( filter );
}
/**
* Return the number of Filters this InternalFilterList contains.
*/
// Since we're storing the filters as a vector, just return
// Vector.size().
int numFilters () {
return m_vFilter.size();
}
public String toString() {
StringBuffer strBuf = new StringBuffer ( 100 );
strBuf.append ( " Match Pattern: \"" + m_strMatchPattern + "\"\n" );
for ( int i = 0; i < m_vFilter.size(); i++ ) {
strBuf.append ( ((LDAPFilter)m_vFilter.elementAt(i)).toString() );
strBuf.append ( "\n" );
}
return strBuf.toString();
}
/**
* Return the requested filter.
*/
LDAPFilter getFilter ( int nFilter ) {
return (LDAPFilter)m_vFilter.elementAt ( nFilter );
}
/**
* Try to match the filter to the given string. This method is called
* when the user types in data. We match the expression (stored in
* m_strMatchPattern) to the value that the user typed in (the
* parameter to this method).
*/
boolean MatchFilter ( PatternMatcherInput matcherValue ) {
matcherValue.setCurrentOffset ( matcherValue.getBeginOffset() );
return m_matcher.contains ( matcherValue, m_patMatch );
}
}

View File

@@ -0,0 +1,159 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap.util;
import java.util.*;
import com.oroinc.text.regex.*;
/**
* Represents an LDAPIntFilterSet object. This is an internal object that
* should never be instantiated directly by the developer.
*/
public class LDAPIntFilterSet {
private Vector m_vLDAPIntFilterList;
private String m_strTag;
private PatternMatcherInput m_matcherTag = null;
private Perl5Matcher m_matcher = null;
/**
* Return a Vector of filters that match botht the tag pattern
* (in Perl5Pattern form), and the string strValue. This method
* should only be called by LDAPFilterDescriptor().
*/
// remember, we have the string (m_strTag), the pattern has
// been precompiled by the LDAPFilterDescriptor (patTag)
Vector getFilters ( Perl5Pattern patTag,
PatternMatcherInput matcherValue ) {
Vector vRet = new Vector();
if ( m_matcherTag == null ) {
m_matcher = new Perl5Matcher();
m_matcherTag = new PatternMatcherInput ( m_strTag );
} else {
m_matcherTag.setCurrentOffset ( m_matcherTag.getBeginOffset() );
}
// Check to see if the strTag (converted into patTag)
// matches the tag string from the file (converted into
// m_matcherTag)
if ( m_matcher.contains ( m_matcherTag, patTag ) ) {
LDAPIntFilterList tmpIntFilterList;
LDAPFilter tmpFilter;
for ( int i = 0; i < m_vLDAPIntFilterList.size(); i++ ) {
tmpIntFilterList =
(LDAPIntFilterList)m_vLDAPIntFilterList.elementAt ( i );
if ( tmpIntFilterList.MatchFilter ( matcherValue ) ) {
for (int j=0; j < tmpIntFilterList.numFilters(); j++ ) {
vRet.addElement ( tmpIntFilterList.getFilter ( j ));
}
// potential BUGBUG, i'm not sure if we want
// to get out of this loop now or if we just
// want to get out of the external loop. For
// now, go with the former.
return vRet;
}
}
}
return vRet;
}
/**
* Create an LDAPIntFilterSet with a given Tag string. The tag
* string specifies which applications or query types should use
* this filter set. It is normally a single token on a line by
* itself in the filter configuration file. <p>
* For more information about the filter configuration file, see
* the man page for ldapfilter.conf.
*/
public LDAPIntFilterSet ( String strTag ) {
m_strTag = strTag;
m_vLDAPIntFilterList = new Vector();
}
/**
* Add a new filter to this filter set.
*
* @exception netscape.ldap.util.BadFilterException
* If the regular expression pattern given in the first token
* is bad.
*/
void newFilter ( LDAPFilter filter ) throws BadFilterException {
LDAPIntFilterList tmpFilterList = new LDAPIntFilterList( filter );
m_vLDAPIntFilterList.addElement ( tmpFilterList );
}
/**
* Append a new filter to the existing set. This happens when the
* LDAPFilterDescriptor object reads a line from the filter
* configuration file that has 2 or 3 tokens.
*/
void appendFilter ( LDAPFilter filter ) {
((LDAPIntFilterList)m_vLDAPIntFilterList.lastElement()).AddFilter ( filter );
}
/**
* Return true if this filter set matches the regular expression
* string that is passed in.
*/
boolean match ( String strTagPat ) {
Perl5Matcher matcher = new Perl5Matcher();
Perl5Compiler compiler = new Perl5Compiler();
PatternMatcherInput input;
Perl5Pattern patTag;
MatchResult result;
try {
patTag = (Perl5Pattern)compiler.compile ( strTagPat );
} catch ( MalformedPatternException e ) {
// Need to do something here.
return false;
}
input = new PatternMatcherInput ( m_strTag );
if ( matcher.contains ( input, patTag ) ) {
return true;
} else {
return false;
}
}
/**
* Print out the String representation of this object. It calls
* the toString() method of all the LDAPFilter objects contained
* within it's set.
*
* @see LDAPFilter#toString()
*/
public String toString() {
StringBuffer strBuf = new StringBuffer ( 2000 );
strBuf.append ( " strTag: " + m_strTag + "\n" );
for ( int i = 0; i < m_vLDAPIntFilterList.size(); i++ ) {
strBuf.append ( " filter #: " + i + "\n" );
strBuf.append (
((LDAPIntFilterList)m_vLDAPIntFilterList.elementAt(i)).toString() );
strBuf.append ( "\n" );
}
return strBuf.toString();
}
}

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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package com.netscape.sasl;
import java.util.Hashtable;
import javax.security.auth.callback.CallbackHandler;
/**
* An interface for creating instances of <tt>SaslClient</tt>.
*
* @see SaslClient
* @see Sasl
*/
public class ClientFactory implements SaslClientFactory {
public ClientFactory() {
_mechanismTable = new Hashtable();
for( int i = 0; i < _mechanismNames.length; i++ ) {
_mechanismTable.put( _mechanismNames[i],
PACKAGENAME + '.' +
_mechanismClasses[i] );
}
}
/**
* Creates a SaslClient using the parameters supplied.
*
* @param mechanisms The non-null list of mechanism names to try.
* Each is the IANA-registered name of a SASL mechanism. (e.g.
* "GSSAPI", "CRAM-MD5").
* @param authorizationId The possibly null authorization ID to
* use. When the SASL authentication completes successfully, the
* entity named by authorizationId is granted access.
* @param protocol The non-null string name of the protocol for
* which the authentication is being performed (e.g., "ldap").
* @param serverName The non-null string name of the server to
* which we are creating an authenticated connection.
* @param props The possibly null properties to be used by the SASL
* mechanisms to configure the authentication exchange. For example,
* "javax.security.sasl.encryption.maximum" might be used to
* specify the maximum key length to use for encryption.
* @param cbh The possibly null callback handler to used by the
* SASL mechanisms to get further information from the
* application/library to complete the authentication. For example,
* a SASL mechanism might require the authentication ID and
* password from the caller.
* @return A possibly null <tt>SaslClient</tt> created using the
* parameters supplied. If null, this factory cannot produce a
* <tt>SaslClient</tt> using the parameters supplied.
* @exception SaslException if it cannot create a
* <tt>SaslClient</tt> because of an error.
*/
public SaslClient createSaslClient(
String[] mechanisms,
String authorizationId,
String protocol,
String serverName,
Hashtable props,
CallbackHandler cbh ) throws SaslException {
String mechName = null;
if ( Sasl.debug ) {
System.out.println(
"ClientFactory.createSaslClient" );
}
for( int i = 0; (mechName == null) &&
(i < mechanisms.length); i++ ) {
mechName = (String)_mechanismTable.get( mechanisms[i] );
}
if ( mechName != null ) {
try {
Class c = Class.forName( mechName );
SaslClient client = (SaslClient)c.newInstance();
if ( Sasl.debug ) {
System.out.println(
"ClientFactory.createSaslClient: newInstance for " +
mechName + " returned " + client);
}
return client;
} catch ( Exception e ) {
System.err.println(
"ClientFactory.createSaslClient: " + e );
}
} else {
if ( Sasl.debug ) {
System.out.println(
"ClientFactory.createSaslClient: does not support " +
"any of the mechanisms" );
for( int i = 0; i < mechanisms.length; i++ ) {
System.out.println( " " + mechanisms[i] );
}
}
}
return null;
}
/**
* Returns an array of names of mechanisms supported by this
* factory.
* @return A non-null array containing IANA-registered SASL
* mechanism names.
*/
public String[] getMechanismNames() {
return _mechanismNames;
}
private final String PACKAGENAME = "com.netscape.sasl.mechanisms";
private final String[] _mechanismNames = { "EXTERNAL" };
private final String[] _mechanismClasses = { "SaslExternal" };
private Hashtable _mechanismTable;
}

View File

@@ -0,0 +1,235 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package com.netscape.sasl;
import java.util.Hashtable;
import javax.security.auth.callback.CallbackHandler;
import java.util.StringTokenizer;
import java.io.*;
/**
* A static class for creating SASL clients and servers.
*<p>
* This class defines the policy of how to locate, load, and instantiate
* SASL clients and servers.
* Currently, only the client methods are available.
*<p>
* For example, an application or library gets a SASL client by doing
* something like:
*<blockquote><pre>
* SaslClient sc = Sasl.createSaslClient(mechanisms,
* authorizationId, protocol, serverName, props, callbackHandler);
*</pre></blockquote>
* It can then proceed to use the client create an authentication connection.
* For example, an LDAP library might use the client as follows:
*<blockquote><pre>
* InputStream is = ldap.getInputStream();
* OutputStream os = ldap.getOutputStream();
* byte[] toServer = sc.createInitialResponse();
* LdapResult res = ldap.sendBindRequest(dn, sc.getName(), toServer);
* while (!sc.isComplete() && res.status == SASL_BIND_IN_PROGRESS) {
* toServer = sc.evaluateChallenge(res.getBytesFromServer());
* if (toServer != null) {
* res = ldap.sendBindRequest(dn, sc.getName(), toServer);
* }
* }
* if (sc.isComplete() && res.status == SUCCESS) {
* // Get the input and output streams; may be unchanged
* is = sc.getInputStream( is );
* os = sc.getOutputStream( os );
* // Use these streams from now on
* ldap.setInputStream( is );
* ldap.setOutputStream( os );
* }
*</pre></blockquote>
*
* IMPLEMENTATION NOTE: To use this class on JDK1.2, the caller needs:
*<ul><tt>
*<li>java.lang.RuntimePermission("getSecurityManager")
*<li>java.lang.RuntimePermission("getClassLoader")
*<li>java.util.PropertyPermission("javax.security.sasl.client.pkgs", "read");
*</tt></ul>
*/
public class Sasl {
private static SaslClientFactory clientFactory = null;
static final boolean debug = false;
// Cannot create one of these
private Sasl() {
}
/**
* The property name containing a list of package names, separated by
* '|'. Each package contains a class named <tt>ClientFactory</tt> that
* implements the <tt>SaslClientFactory</tt> interface.
* Its value is "javax.security.sasl.client.pkgs".
*/
public static final String CLIENTPKGS = "javax.security.sasl.client.pkgs";
/**
* Creates a SaslClient using the parameters supplied.
* The algorithm for selection is as follows:
*<ol>
*<li>If a factory has been installed via <tt>setSaslClientFactory()</tt>,
* try it first. If non-null answer produced, return it.
*<li>The <tt>javax.security.sasl.client.pkgs</tt> property contains
* a '|'-separated list of package names. Each package contains a
* class named <tt>ClientFactory</tt>. Load each factory
* and try to create a <tt>SaslClient</tt>.
* Repeat this for
* each package on the list until a non-null answer is produced.
* If non-null answer produced, return it.
*<li>Repeat previous step using the <tt>javax.security.sasl.client.pkgs</tt>
* System property.
*<li>If no non-null answer produced, return null.
*</ol>
*
* @param mechanisms The non-null list of mechanism names to try. Each is the
* IANA-registered name of a SASL mechanism. (e.g. "GSSAPI", "CRAM-MD5").
* @param authorizationId The possibly null authorization ID to use. When
* the SASL authentication completes successfully, the entity named
* by authorizationId is granted access.
* @param protocol The non-null string name of the protocol for which
* the authentication is being performed (e.g., "ldap").
* @param serverName The non-null string name of the server to which
* we are creating an authenticated connection.
* @param props The possibly null properties to be used by the SASL
* mechanisms to configure the authentication exchange. For example,
* "javax.security.sasl.encryption.maximum" might be used to specify
* the maximum key length to use for encryption.
* @param cbh The possibly null callback handler to used by the SASL
* mechanisms to get further information from the application/library
* to complete the authentication. For example, a SASL mechanism might
* require the authentication ID and password from the caller.
*@return A possibly null <tt>SaslClient</tt> created using the parameters
* supplied. If null, cannot find a <tt>SaslClientFactory</tt>
* that will produce one.
*@exception SaslException If cannot create a <tt>SaslClient</tt> because
* of an error.
*/
public static SaslClient createSaslClient(
String[] mechanisms,
String authorizationId,
String protocol,
String serverName,
Hashtable props,
CallbackHandler cbh) throws SaslException {
if (debug) {
System.out.println("Sasl.createSaslClient");
}
SaslClient mech = null;
// If factory has been set, try it first
if (clientFactory != null) {
mech = clientFactory.createSaslClient(
mechanisms, authorizationId,
protocol, serverName, props, cbh);
}
// No mechanism produced
if (mech == null) {
String pkgs = (props == null) ? null :
(String) props.get(CLIENTPKGS);
// Try properties argument
if (pkgs != null) {
mech = loadFromPkgList(pkgs, mechanisms,
authorizationId,
protocol, serverName,
props, cbh);
}
// Try system properties
if (mech == null &&
(pkgs = System.getProperty(CLIENTPKGS)) != null) {
mech = loadFromPkgList(pkgs, mechanisms,
authorizationId,
protocol, serverName,
props, cbh);
}
}
return mech;
}
private static SaslClient loadFromPkgList(String pkgs,
String[] mechanisms,
String authorizationId,
String protocol,
String serverName,
Hashtable props,
CallbackHandler cbh)
throws SaslException {
StringTokenizer packagePrefixIter = new StringTokenizer(pkgs, "|");
SaslClient mech = null;
SaslClientFactory fac = null;
while (mech == null && packagePrefixIter.hasMoreTokens()) {
String pkg = packagePrefixIter.nextToken().trim();
String clsName = pkg + ".ClientFactory";
if (debug) {
System.out.println("Sasl.loadFromPkgList: " + clsName);
}
Class cls = null;
try {
cls = Class.forName(clsName);
} catch (Exception e) {
System.err.println( "Sasl.loadFromPkgList: " + e );
}
if (cls != null) {
try {
fac = (SaslClientFactory) cls.newInstance();
} catch (InstantiationException e) {
throw new SaslException(
"Cannot instantiate " + clsName);
} catch (IllegalAccessException e) {
throw new SaslException(
"Cannot access constructor of " + clsName);
}
mech = fac.createSaslClient(mechanisms, authorizationId,
protocol, serverName, props,
cbh);
}
}
return mech;
}
/**
* Sets the default <tt>SaslClientFactory</tt> to use.
* This method sets <tt>fac</tt> to be the default factory.
* It can only be called with a non-null value once per VM.
* If a factory has been set already, this method throws
* <tt>IllegalStateException</tt>.
* @param fac The possibly null factory to set. If null, doesn't
* do anything.
* @exception IllegalStateException If factory already set.
*/
public static void setSaslClientFactory(SaslClientFactory fac) {
if (clientFactory != null) {
throw new IllegalStateException (
"SaslClientFactory already defined");
}
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkSetFactory();
}
clientFactory = fac;
}
}

View File

@@ -0,0 +1,140 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package com.netscape.sasl;
import java.util.Hashtable;
import java.io.*;
/**
* Performs SASL authentication as a client.
*<p>
* A protocol library such as one for LDAP gets an instance of this
* class in order to perform authentication defined by a specific SASL
* mechanism. Invoking methods on the <tt>SaslClient</tt> instance
* process challenges and create responses according to the SASL
* mechanism implemented by the <tt>SaslClient</tt>.
* As the authentication proceeds, the instance
* encapsulates the state of a SASL client's authentication exchange.
*<p>
* Here's an example of how an LDAP library might use a <tt>SaslClient</tt>.
* It first gets an instance of a <tt>SaslClient</tt>:
*<blockquote><pre>
* SaslClient sc = Sasl.createSaslClient(mechanisms,
* authorizationId, protocol, serverName, props, callbackHandler);
*</pre></blockquote>
* It can then proceed to use the client for authentication.
* For example, an LDAP library might use the client as follows:
*<blockquote><pre>
* InputStream is = ldap.getInputStream();
* OutputStream os = ldap.getOutputStream();
* byte[] toServer = sc.createInitialResponse();
* LdapResult res = ldap.sendBindRequest(dn, sc.getName(), toServer);
* while (!sc.isComplete() && res.status == SASL_BIND_IN_PROGRESS) {
* toServer = sc.evaluateChallenge(res.getBytesFromServer());
* if (toServer != null) {
* res = ldap.sendBindRequest(dn, sc.getName(), toServer);
* }
* }
* if (sc.isComplete() && res.status == SUCCESS) {
* // Get the input and output streams; may be unchanged
* is = sc.getInputStream( is );
* os = sc.getOutputStream( os );
* // Use these streams from now on
* ldap.setInputStream( is );
* ldap.setOutputStream( os );
* }
*</pre></blockquote>
*
* Note that the call to <tt>createInitialResponse()</tt> is optional.
* Protocols such as IMAP4 do not invoke it but instead only use
* <tt>evaluateChallenge()</tt>, possibly with an empty challenge.
* It is the responsibility of the <tt>SaslClient</tt> implementation
* for a mechanism to take this into account so that it behaves properly
* regardless of whether <tt>createInitialResponse()</tt> is called.
*
* @see Sasl
* @see SaslClientFactory
*/
public abstract interface SaslClient {
/**
* Returns the IANA-registered mechanism name of this SASL client.
* (e.g. "CRAM-MD5", "GSSAPI").
* @return A non-null string representing the IANA-registered mechanism name.
*/
public abstract String getMechanismName();
/**
* Retrieves the initial response.
*
* @return The possibly null byte array containing the initial response.
* It is null if the mechanism does not have an initial response.
* @exception SaslException If an error occurred while creating
* the initial response.
*/
public abstract byte[] createInitialResponse() throws SaslException;
/**
* Evaluates the challenge data and generates a response.
*
* @param challenge The non-null challenge sent from the server.
*
* @return The possibly null reponse to send to the server.
* It is null if the challenge accompanied a "SUCCESS" status and the challenge
* only contains data for the client to update its state and no response
* needs to be sent to the server.
* @exception SaslException If an error occurred while processing
* the challenge or generating a response.
*/
public abstract byte[] evaluateChallenge(byte[] challenge)
throws SaslException;
/**
* Determines whether the authentication exchange has completed.
* @return true if the authentication exchange has completed; false otherwise.
*/
public abstract boolean isComplete();
/**
* Retrieves an input stream for the session. It may return
* the same stream that is passed in, if no processing is to be
* done by the client object.
*
* This method can only be called if isComplete() returns true.
* @param is The original input stream for reading from the server.
* @return An input stream for reading from the server, which
* may include processing the original stream.
* @exception IOException If the authentication exchange has not completed
* or an error occurred while getting the stream.
*/
public abstract InputStream getInputStream(InputStream is) throws IOException;
/**
* Retrieves an output stream for the session. It may return
* the same stream that is passed in, if no processing is to be
* done by the client object.
*
* This method can only be called if isComplete() returns true.
* @param is The original output stream for writing to the server.
* @return An output stream for writing to the server, which
* may include processing the original stream.
* @exception IOException If the authentication exchange has not completed
* or an error occurred while getting the stream.
*/
public abstract OutputStream getOutputStream(OutputStream os) throws IOException;
}

View File

@@ -0,0 +1,69 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package com.netscape.sasl;
import java.util.Hashtable;
import javax.security.auth.callback.CallbackHandler;
/**
* An interface for creating instances of <tt>SaslClient</tt>.
*
* @see SaslClient
* @see Sasl
*/
public abstract interface SaslClientFactory {
/**
* Creates a SaslClient using the parameters supplied.
*
* @param mechanisms The non-null list of mechanism names to try. Each is the
* IANA-registered name of a SASL mechanism. (e.g. "GSSAPI", "CRAM-MD5").
* @param authorizationId The possibly null authorization ID to use. When
* the SASL authentication completes successfully, the entity named
* by authorizationId is granted access.
* @param protocol The non-null string name of the protocol for which
* the authentication is being performed (e.g., "ldap").
* @param serverName The non-null string name of the server to which
* we are creating an authenticated connection.
* @param props The possibly null properties to be used by the SASL
* mechanisms to configure the authentication exchange. For example,
* "javax.security.sasl.encryption.maximum" might be used to specify
* the maximum key length to use for encryption.
* @param cbh The possibly null callback handler to used by the SASL
* mechanisms to get further information from the application/library
* to complete the authentication. For example, a SASL mechanism might
* require the authentication ID and password from the caller.
*@return A possibly null <tt>SaslClient</tt> created using the parameters
* supplied. If null, this factory cannot produce a <tt>SaslClient</tt>
* using the parameters supplied.
*@exception SaslException If cannot create a <tt>SaslClient</tt> because
* of an error.
*/
public abstract SaslClient createSaslClient(
String[] mechanisms,
String authorizationId,
String protocol,
String serverName,
Hashtable props,
CallbackHandler cbh) throws SaslException;
/**
* Returns an array of names of mechanisms supported by this factory.
* @return A non-null array containing a IANA-registered SASL mechanism names.
*/
public abstract String[] getMechanismNames();
}

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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package com.netscape.sasl;
/**
* This class represents an error that has occurred when using SASL.
*
*/
public class SaslException extends java.io.IOException {
/**
* The possibly null root cause exception.
* @serial
*/
private Throwable exception;
/**
* Constructs a new instance of <tt>SaslException</tt>.
* The root exception and the detailed message are null.
*/
public SaslException () {
super();
}
/**
* Constructs a new instance of <tt>SaslException</tt> with a detailed message.
* The root exception is null.
* @param detail A possibly null string containing details of the exception.
*
* @see java.lang.Throwable#getMessage
*/
public SaslException (String detail) {
super(detail);
}
/**
* Constructs a new instance of <tt>SaslException</tt> with a detailed message
* and a root exception.
* For example, a SaslException might result from a problem with
* the callback handler, which might throw a NoSuchCallbackException if
* it does not support the requested callback, or throw an IOException
* if it had problems obtaining data for the callback. The
* SaslException's root exception would be then be the exception thrown
* by the callback handler.
*
* @param detail A possibly null string containing details of the exception.
* @param ex A possibly null root exception that caused this exception.
*
* @see java.lang.Throwable#getMessage
* @see #getException
*/
public SaslException (String detail, Throwable ex) {
super(detail);
exception = ex;
}
/**
* Returns the root exception that caused this exception.
* @return The possibly null root exception that caused this exception.
*/
public Throwable getException() {
return exception;
}
/**
* Prints this exception's stack trace to <tt>System.err</tt>.
* If this exception has a root exception; the stack trace of the
* root exception is printed to <tt>System.err</tt> instead.
*/
public void printStackTrace() {
printStackTrace( System.err );
}
/**
* Prints this exception's stack trace to a print stream.
* If this exception has a root exception; the stack trace of the
* root exception is printed to the print stream instead.
* @param ps The non-null print stream to which to print.
*/
public void printStackTrace(java.io.PrintStream ps) {
if ( exception != null ) {
String superString = super.toString();
synchronized ( ps ) {
ps.print(superString
+ (superString.endsWith(".") ? "" : ".")
+ " Root exception is ");
exception.printStackTrace( ps );
}
} else {
super.printStackTrace( ps );
}
}
/**
* Prints this exception's stack trace to a print writer.
* If this exception has a root exception; the stack trace of the
* root exception is printed to the print writer instead.
* @param ps The non-null print writer to which to print.
*/
public void printStackTrace(java.io.PrintWriter pw) {
if ( exception != null ) {
String superString = super.toString();
synchronized (pw) {
pw.print(superString
+ (superString.endsWith(".") ? "" : ".")
+ " Root exception is ");
exception.printStackTrace( pw );
}
} else {
super.printStackTrace( pw );
}
}
/**
* Returns the string representation of this exception.
* The string representation contains
* this exception's class name, its detailed messsage, and if
* it has a root exception, the string representation of the root
* exception. This string representation
* is meant for debugging and not meant to be interpreted
* programmatically.
* @return The non-null string representation of this exception.
* @see java.lang.Throwable#getMessage
*/
public String toString() {
String answer = super.toString();
if (exception != null && exception != this) {
answer += " [Root exception is " + exception.toString() + "]";
}
return answer;
}
}

View File

@@ -0,0 +1,121 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package com.netscape.sasl.mechanisms;
import java.io.*;
import com.netscape.sasl.*;
/**
* This class provides the implementation of the EXTERNAL mechanism driver.
* This mechanism is passed in the SASL External bind request to retrieve the
* current result code from the server.
*/
public class SaslExternal implements SaslClient {
/**
* Default constructor
*/
public SaslExternal() {
}
/**
* Retrieves the initial response.
*
* @return The possibly null byte array containing the initial response.
* It is null if the mechanism does not have an initial response.
* @exception SaslException If an error occurred while creating
* the initial response.
*/
public byte[] createInitialResponse() throws SaslException {
return null;
}
/**
* Evaluates the challenge data and generates a response.
*
* @param challenge The non-null challenge sent from the server.
*
* @return The possibly null reponse to send to the server.
* It is null if the challenge accompanied a "SUCCESS" status
* and the challenge only contains data for the client to
* update its state and no response needs to be sent to the server.
* @exception SaslException If an error occurred while processing
* the challenge or generating a response.
*/
public byte[] evaluateChallenge(byte[] challenge)
throws SaslException {
return null;
}
/**
* Returns the name of mechanism driver.
* @return The mechanism name.
*/
public String getMechanismName() {
return MECHANISM_NAME;
}
/**
* The method may be called at any time to determine if the authentication
* process is finished.
* @return <CODE>true</CODE> if authentication is complete. For this class,
* always returns <CODE>true</CODE>.
*/
public boolean isComplete() {
return true;
}
/**
* Retrieves an input stream for the session. It may return
* the same stream that is passed in, if no processing is to be
* done by the client object.
*
* This method can only be called if isComplete() returns true.
* @param is The original input stream for reading from the server.
* @return An input stream for reading from the server, which
* may include processing the original stream. For this class, the
* input parameter is always returned.
* @exception IOException If the authentication exchange has not completed
* or an error occurred while getting the stream.
*/
public InputStream getInputStream(InputStream is)
throws IOException {
return is;
}
/**
* Retrieves an output stream for the session. It may return
* the same stream that is passed in, if no processing is to be
* done by the client object.
*
* This method can only be called if isComplete() returns true.
* @param is The original output stream for writing to the server.
* @return An output stream for writing to the server, which
* may include processing the original stream. For this class, the
* input parameter is always returned.
* @exception IOException If the authentication exchange has not completed
* or an error occurred while getting the stream.
*/
public OutputStream getOutputStream(OutputStream os)
throws IOException {
return os;
}
private final static String MECHANISM_NAME = "EXTERNAL";
}

Binary file not shown.

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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.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));
}
} catch (Exception e) {
throw new LDAPException("Invoking "+methodName+": "+
e.toString(), LDAPException.PARAM_ERROR);
}
return null;
}
static java.lang.reflect.Method getMethod(String packageName,
String methodName, String[] args) throws LDAPException {
try {
java.lang.reflect.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 = (java.lang.reflect.Method)(m_methodLookup.get(key)))
!= null)
return method;
Class c = Class.forName(packageName);
java.lang.reflect.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)
return false;
for (int i=0; i<params.length; i++) {
if (!params[i].getName().equals(args[i]))
return false;
}
return true;
}
private static Hashtable m_methodLookup = new Hashtable();
}

View File

@@ -0,0 +1,438 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import java.util.*;
import java.io.*;
import javax.security.auth.callback.CallbackHandler;
/**
* Encapsulates a connection to an LDAP server, providing access to the input queue
* for messages received.
*
* @version 1.0
*/
public interface LDAPAsynchronousConnection {
/**
* Adds an entry to the directory.
*
* @param entry LDAPEntry object specifying the distinguished name and
* attributes of the new entry.
* @param listener Handler for messages returned from a server in response
* to this request. If it is null, a listener object is created internally.
* @param cons Constraints specific to the operation.
* @return LDAPSearchListener Handler for messages returned from a server
* in response to this request.
* @exception LDAPException Failed to send request.
* @see netscape.ldap.LDAPEntry
* @see netscape.ldap.LDAPResponseListener
*/
public LDAPResponseListener add(LDAPEntry entry,
LDAPResponseListener listener)
throws LDAPException;
/**
* Adds an entry to the directory and allows you to specify constraints
* for this LDAP add operation by using an <CODE>LDAPConstraints</CODE>
* object. For example, you can specify whether or not to follow referrals.
* You can also apply LDAP v3 controls to the operation.
* <P>
*
* @param entry LDAPEntry object specifying the distinguished name and
* attributes of the new entry.
* @param listener Handler for messages returned from a server in response
* to this request. If it is null, a listener object is created internally.
* @param cons Constraints specific to the operation.
* @return LDAPResponseListener Handler for messages returned from a server
* in response to this request.
* @exception LDAPException Failed to send request.
* @see netscape.ldap.LDAPEntry
* @see netscape.ldap.LDAPResponseListener
* @see netscape.ldap.LDAPConstraints
*/
public LDAPResponseListener add(LDAPEntry entry,
LDAPResponseListener listener,
LDAPConstraints cons)
throws LDAPException;
/**
* Authenticates to the LDAP server (that the object is currently
* connected to) using the specified name and password. 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 dn If non-null and non-empty, specifies that the connection
* and all operations through it should be authenticated with dn as the
* distinguished name.
* @param passwd If non-null and non-empty, specifies that the connection
* and all operations through it should be authenticated with dn as the
* distinguished name and passwd as password.
* @param listener Handler for messages returned from a server in response
* to this request. If it is null, a listener object is created internally.
* @return LDAPResponseListener Handler for messages returned from a server
* in response to this request.
* @exception LDAPException Failed to send request.
* @see netscape.ldap.LDAPResponseListener
*/
public LDAPResponseListener bind(String dn,
String passwd,
LDAPResponseListener listener)
throws LDAPException;
/**
* Authenticates to the LDAP server (that the object is currently
* connected to) using the specified name and password and allows you
* to specify constraints for this LDAP add operation by using an
* <CODE>LDAPConstraints</CODE> object. 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 dn If non-null and non-empty, specifies that the connection
* and all operations through it should be authenticated with dn as the
* distinguished name.
* @param passwd If non-null and non-empty, specifies that the connection
* and all operations through it should be authenticated with dn as the
* distinguished name and passwd as password.
* @param listener Handler for messages returned from a server in response
* to this request. If it is null, a listener object is created internally.
* @param cons Constraints specific to the operation.
* @return LDAPResponseListener Handler for messages returned from a server
* in response to this request.
* @exception LDAPException Failed to send request.
* @see netscape.ldap.LDAPResponseListener
* @see netscape.ldap.LDAPConstraints
*/
public LDAPResponseListener bind(String dn,
String passwd,
LDAPResponseListener listener,
LDAPConstraints cons)
throws LDAPException;
/**
* Deletes the entry for the specified DN from the directory.
*
* @param dn Distinguished name of the entry to delete.
* @param listener Handler for messages returned from a server in response
* to this request. If it is null, a listener object is created internally.
* @return LDAPResponseListener Handler for messages returned from a server
* in response to this request.
* @exception LDAPException Failed to send request.
* @see netscape.ldap.LDAPResponseListener
* @see netscape.ldap.LDAPConstraints
*/
public LDAPResponseListener delete(String dn,
LDAPResponseListener listener)
throws LDAPException;
/**
* Deletes the entry for the specified DN from the directory.
*
* @param dn Distinguished name of the entry to delete.
* @param listener Handler for messages returned from a server in response
* to this request. If it is null, a listener object is created internally.
* @param cons Constraints specific to the operation.
* @return LDAPResponseListener Handler for messages returned from a server
* in response to this request.
* @exception LDAPException Failed to send request.
* @see netscape.ldap.LDAPResponseListener
* @see netscape.ldap.LDAPConstraints
*/
public LDAPResponseListener delete(String dn,
LDAPResponseListener listener,
LDAPConstraints cons)
throws LDAPException;
/**
* Makes a single change to an existing entry in the directory (for
* example, changes the value of an attribute, adds a new attribute
* value, or removes an existing attribute value).<BR>
* The LDAPModification object specifies both the change to be made and
* the LDAPAttribute value to be changed.
*
* @param dn Distinguished name of the entry to modify.
* @param mod A single change to be made to an entry.
* @param listener Handler for messages returned from a server in response
* to this request. If it is null, a listener object is created internally.
* @return LDAPResponseListener Handler for messages returned from a server
* in response to this request.
* @exception LDAPException Failed to send request.
* @see netscape.ldap.LDAPModification
* @see netscape.ldap.LDAPResponseListener
*/
public LDAPResponseListener modify(String dn,
LDAPModification mod,
LDAPResponseListener listener)
throws LDAPException;
/**
* Makes a single change to an existing entry in the directory (for
* example, changes the value of an attribute, adds a new attribute
* value, or removes an existing attribute value).<BR>
* The LDAPModification object specifies both the change to be made and
* the LDAPAttribute value to be changed.
*
* @param dn Distinguished name of the entry to modify.
* @param mod A single change to be made to an entry.
* @param listener Handler for messages returned from a server in response
* to this request. If it is null, a listener object is created internally.
* @param cons Constraints specific to the operation.
* @return LDAPResponseListener Handler for messages returned from a server
* in response to this request.
* @exception LDAPException Failed to send request.
* @see netscape.ldap.LDAPModification
* @see netscape.ldap.LDAPResponseListener
* @see netscape.ldap.LDAPConstraints
*/
public LDAPResponseListener modify(String dn,
LDAPModification mod,
LDAPResponseListener listener,
LDAPConstraints cons)
throws LDAPException;
/**
* Makes a set of changes to an existing entry in the directory (for
* example, changes attribute values, adds new attribute values, or
* removes existing attribute values).
* <P>
* @param dn Distinguished name of the entry to modify.
* @param mods A set of modifications to be made to the entry.
* @param listener Handler for messages returned from a server in response
* to this request. If it is null, a listener object is created internally.
* @return LDAPResponseListener Handler for messages returned from a server
* in response to this request.
* @exception LDAPException Failed to send request.
* @see netscape.ldap.LDAPModificationSet
* @see netscape.ldap.LDAPResponseListener
*/
public LDAPResponseListener modify(String dn,
LDAPModificationSet mods,
LDAPResponseListener listener)
throws LDAPException;
/**
* Makes a set of changes to an existing entry in the directory (for
* example, changes attribute values, adds new attribute values, or
* removes existing attribute values).
*
* @param dn Distinguished name of the entry to modify.
* @param mods A set of modifications to be made to the entry.
* @param listener Handler for messages returned from a server in response
* to this request. If it is null, a listener object is created internally.
* @param cons Constraints specific to the operation.
* @return LDAPResponseListener Handler for messages returned from a server
* in response to this request.
* @exception LDAPException Failed to send request.
* @see netscape.ldap.LDAPModificationSet
* @see netscape.ldap.LDAPResponseListener
* @see netscape.ldap.LDAPConstraints
*/
public LDAPResponseListener modify(String dn,
LDAPModificationSet mods,
LDAPResponseListener listener,
LDAPConstraints cons)
throws LDAPException;
/**
* Renames an existing entry in the directory.
*
* @param dn Current distinguished name of the entry.
* @param newRdn New relative distinguished name for the entry.
* @param deleteOldRdn If true, the old name is not retained as an
* attribute value.
* @param listener Handler for messages returned from a server in response
* to this request. If it is null, a listener object is created internally.
* @return LDAPResponseListener Handler for messages returned from a server
* in response to this request.
* @exception LDAPException Failed to send request.
* @see netscape.ldap.LDAPResponseListener
*/
public LDAPResponseListener rename(String dn,
String newRdn,
boolean deleteOldRdn,
LDAPResponseListener listener)
throws LDAPException;
/**
* Renames an existing entry in the directory.
*
* @param dn Current distinguished name of the entry.
* @param newRdn New relative distinguished name for the entry.
* @param deleteOldRdn If true, the old name is not retained as an
* @param listener Handler for messages returned from a server in response
* to this request. If it is null, a listener object is created internally.
* @param cons Constraints specific to the operation.
* @return LDAPResponseListener Handler for messages returned from a server
* in response to this request.
* @exception LDAPException Failed to send request.
* @see netscape.ldap.LDAPResponseListener
* @see netscape.ldap.LDAPConstraints
*/
public LDAPResponseListener rename(String dn,
String newRdn,
boolean deleteOldRdn,
LDAPResponseListener listener,
LDAPConstraints cons)
throws LDAPException;
/**
* Performs the search specified by the criteria that you enter. <P>
* To abandon the search, use the <CODE>abandon</CODE> method.
*
* @param base The base distinguished name to search from
* @param scope The scope of the entries to search. You can specify one
* of the following: <P>
* <UL>
* <LI><CODE>LDAPv2.SCOPE_BASE</CODE> (search only the base DN) <P>
* <LI><CODE>LDAPv2.SCOPE_ONE</CODE>
* (search only entries under the base DN) <P>
* <LI><CODE>LDAPv2.SCOPE_SUB</CODE>
* (search the base DN and all entries within its subtree) <P>
* </UL>
* <P>
* @param filter Search filter specifying the search criteria.
* @param attrs List of attributes that you want returned in the
* search results.
* @param typesOnly If true, returns the names but not the values of the
* attributes found. If false, returns the names and values for
* attributes found
* @param listener Handler for messages returned from a server in response
* to this request. If it is null, a listener object is created internally.
* @return LDAPSearchListener Handler for messages returned from a server
* in response to this request.
* @exception LDAPException Failed to send request.
* @see netscape.ldap.LDAPAsynchronousConnection#abandon(netscape.ldap.LDAPSearchListener)
*/
public LDAPSearchListener search(String base,
int scope,
String filter,
String attrs[],
boolean typesOnly,
LDAPSearchListener listener)
throws LDAPException;
/**
* Performs the search specified by the criteria that you enter.
* This method also allows you to specify constraints for the search
* (such as the maximum number of entries to find or the
* maximum time to wait for search results). <P>
* To abandon the search, use the <CODE>abandon</CODE> method.
*
* @param base The base distinguished name to search from
* @param scope The scope of the entries to search. You can specify one
* of the following: <P>
* <UL>
* <LI><CODE>LDAPv2.SCOPE_BASE</CODE> (search only the base DN) <P>
* <LI><CODE>LDAPv2.SCOPE_ONE</CODE>
* (search only entries under the base DN) <P>
* <LI><CODE>LDAPv2.SCOPE_SUB</CODE>
* (search the base DN and all entries within its subtree) <P>
* </UL>
* <P>
* @param filter Search filter specifying the search criteria.
* @param attrs List of attributes that you want returned in the search
* results.
* @param typesOnly If true, returns the names but not the values of the
* attributes found. If false, returns the names and values for
* attributes found.
* @param listener Handler for messages returned from a server in response
* to this request. If it is null, a listener object is created internally.
* @param cons Constraints specific to this search (for example, the
* maximum number of entries to return).
* @return LDAPSearchListener Handler for messages returned from a server
* in response to this request.
* @exception LDAPException Failed to send request.
* @see netscape.ldap.LDAPAsynchronousConnection#abandon(netscape.ldap.LDAPSearchListener)
*/
public LDAPSearchListener search(String base,
int scope,
String filter,
String attrs[],
boolean typesOnly,
LDAPSearchListener listener,
LDAPSearchConstraints cons)
throws LDAPException;
/**
* Compare an attribute value with one in the directory. The result can
* be obtained by calling <CODE>getResultCode</CODE> on the
* <CODE>LDAPResponse</CODE> from the <CODE>LDAPResponseListener</CODE>.
* The code will be <CODE>LDAPException.COMPARE_TRUE</CODE> or
* <CODE>LDAPException.COMPARE_FALSE</CODE>.
*
* @param dn Distinguished name of the entry to compare.
* @param attr Attribute with a value to compare.
* @param listener Handler for messages returned from a server in response
* to this request. If it is null, a listener object is created internally.
* @return LDAPResponseListener Handler for messages returned from a server
* in response to this request.
* @exception LDAPException Failed to send request.
*/
public LDAPResponseListener compare(String dn,
LDAPAttribute attr,
LDAPResponseListener listener)
throws LDAPException;
/**
* Compare an attribute value with one in the directory. The result can
* be obtained by calling <CODE>getResultCode</CODE> on the
* <CODE>LDAPResponse</CODE> from the <CODE>LDAPResponseListener</CODE>.
* The code will be <CODE>LDAPException.COMPARE_TRUE</CODE> or
* <CODE>LDAPException.COMPARE_FALSE</CODE>.
*
* @param dn Distinguished name of the entry to compare.
* @param attr Attribute with a value to compare.
* @param listener Handler for messages returned from a server in response
* to this request. If it is null, a listener object is created internally.
* @param cons Constraints specific to this operation.
* @return LDAPResponseListener Handler for messages returned from a server
* in response to this request.
* @exception LDAPException Failed to send request.
*/
public LDAPResponseListener compare(String dn,
LDAPAttribute attr,
LDAPResponseListener listener,
LDAPConstraints cons)
throws LDAPException;
/**
* Cancels the ldap request with the specified id and discards
* any results already received.
*
* @param id A LDAP request id
* @exception LDAPException Failed to send request.
*/
public void abandon(int id) throws LDAPException;
/**
* Cancels all outstanding search requests associated with this
* LDAPSearchListener object and discards any results already received.
*
* @param searchlistener A search listener returned from a search.
* @exception LDAPException Failed to send request.
*/
public void abandon(LDAPSearchListener searchlistener)
throws LDAPException;
}

View File

@@ -0,0 +1,530 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import java.io.*;
import java.util.*;
import netscape.ldap.ber.stream.*;
/**
* Represents the name and values of an attribute in an entry.
*
* @version 1.0
* @see netscape.ldap.LDAPAttributeSet
*/
public class LDAPAttribute {
private String name = null;
private byte[] nameBuf = null;
/**
* Internally, it 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();
}
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 a array for the values of the attribute as <CODE>String</CODE> objects.
* @return Array of attribute values. Each element in the array
* will be 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
* will be 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 an array for the values of the attribute in <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 to extract the subtypes from
* @return Array of subtypes, or null (if the name has no subtypes)
* @see netscape.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 netscape.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 netscape.ldap.LDAPAttribute#getSubtypes
*/
public String getBaseName() {
return getBaseName(getName());
}
/**
* Report if 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 that you want to check for
* @return true if the attribute name contains the specified subtype
* @see netscape.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;
}
/**
* Report 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 if 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 netscape.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 that you want 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 that you want 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 that you
* want 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 that you want 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 that you want removed.
*/
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 that you want removed.
*/
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 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 {
sb.append(new String(val, "UTF8"));
} catch (Exception e) {
if (val != null) {
sb.append(val.length);
sb.append(" bytes");
}
else {
sb.append("null value");
}
}
}
}
return "{type='" + getName() + "', values='" + sb.toString() + "'}";
}
/**
* Retrieves the string representation of 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,401 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import java.util.*;
/**
* The definition of an attribute type 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 attribute type.
* According to the RFC, the description of an attribute type can
* include the following information:
* <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 or not 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>
*
* You can get the name, OID, and description of this attribute type
* 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 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 netscape.ldap.LDAPSchemaElement
**/
public class LDAPAttributeSchema extends LDAPSchemaElement {
/**
* Construct a blank element.
*/
protected LDAPAttributeSchema() {
super();
}
/**
* Constructs an attribute type definition, using the specified
* information.
* @param name Name 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 syntax Syntax of this attribute type. The value of this
* argument can be one of the following:
* <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)
* </UL>
* @param single <CODE>true</CODE> if the attribute type is single-valued.
*/
public LDAPAttributeSchema( String name, String oid, String description,
int syntax, boolean single ) {
super( name, oid, description );
attrName = "attributetypes";
this.syntax = syntax;
this.syntaxString = internalSyntaxToString();
this.single = single;
}
/**
* Constructs an attribute type definition, using the specified
* information.
* @param name Name 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.
*/
public LDAPAttributeSchema( String name, String oid, String description,
String syntaxString, boolean single ) {
super( name, oid, description );
attrName = "attributetypes";
this.syntaxString = syntaxString;
this.syntax = syntaxCheck( syntaxString );
this.single = single;
}
/**
* Constructs an attribute type definition based on a description in
* the AttributeTypeDescription 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 "attributetypes" attribute 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 ) {
syntaxString = val;
syntax = syntaxCheck( val );
}
single = properties.containsKey( "SINGLE-VALUE" );
}
/**
* Gets the syntax of the attribute type.
* @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 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.
*/
public String getSyntaxString() {
return syntaxString;
}
/**
* 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 single;
}
protected String internalSyntaxToString() {
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 = syntaxString;
}
return s;
}
protected 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;
}
/**
* 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();
s += getValue( SUPERIOR, false );
String val = getOptionalValues( MATCHING_RULES );
if ( val.length() > 0 ) {
s += val + ' ';
}
s += getValue( SYNTAX, quotingBug );
s += ' ';
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;
}
/**
* Get the definition of the attribute type in a user friendly format.
* This is the format that the attribute type definition uses when
* you print the attribute type or the schema.
* @return Definition of the attribute type in a user friendly format.
*/
public String toString() {
String s = "Name: " + name + "; OID: " + oid + "; Type: ";
s += syntaxToString();
s += "; Description: " + description + "; ";
if ( single ) {
s += "single-valued";
} else {
s += "multi-valued";
}
s += getQualifierString( EXPLICIT );
return s;
}
protected int syntaxCheck( String syntax ) {
int i = unknown;
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;
}
/**
* Parses an attribute schema definition to see if the SYNTAX value
* is quoted. It shouldn't be (according to RFC 2252), but it is for
* some LDAP servers. It will either be:<BR>
* <CODE>SYNTAX 1.3.6.1.4.1.1466.115.121.1.15</CODE> or<BR>
* <CODE>SYNTAX '1.3.6.1.4.1.1466.115.121.1.15'</CODE>
* @param raw Definition of the attribute type in the
* AttributeTypeDescription format.
*/
static boolean isSyntaxQuoted( String raw ) {
int ind = raw.indexOf( " SYNTAX " );
if ( ind >= 0 ) {
ind += 8;
int l = raw.length() - ind;
// Extract characters
char[] ch = new char[l];
raw.getChars( ind, raw.length(), ch, 0 );
ind = 0;
// Skip to ' or start of syntax value
while( (ind < ch.length) && (ch[ind] == ' ') ) {
ind++;
}
if ( ind < ch.length ) {
return ( ch[ind] == '\'' );
}
}
return false;
}
// 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";
public static final String SYNTAX = "SYNTAX";
protected int syntax = unknown;
protected String syntaxString = null;
protected boolean single = false;
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 tracked explicitly
static final String[] EXPLICIT = { SINGLE,
OBSOLETE,
COLLECTIVE,
NO_USER_MODIFICATION,
SYNTAX};
}

View File

@@ -0,0 +1,400 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import java.util.*;
import netscape.ldap.client.*;
import netscape.ldap.client.opers.*;
/**
* Represents a set of attributes (for example, the set of attributes
* in an entry).
*
* @version 1.0
* @see netscape.ldap.LDAPAttribute
*/
public class LDAPAttributeSet implements Cloneable
{
Hashtable 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 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() {
}
/**
* Constructs an attribute set.
* @param attrs The list of attributes.
*/
public LDAPAttributeSet( LDAPAttribute[] attrs ) {
this.attrs = attrs;
}
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 an enumeration of the attributes in this attribute set.
* @return Enumeration of the attributes in this set.
*/
public Enumeration getAttributes () {
Vector v = new Vector();
synchronized(this) {
for (int i=0; i<attrs.length; i++) {
v.addElement(attrs[i]);
}
}
return v.elements();
}
/**
* 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
* that you want to find in 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 netscape.ldap.LDAPAttribute
* @see netscape.ldap.LDAPAttributeSet#getAttribute
* @see netscape.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.hasMoreElements() ) {
searchTypes[i] = (String)st.nextElement();
i++;
}
Enumeration attrEnum = getAttributes();
while( attrEnum.hasMoreElements() ) {
LDAPAttribute attr = (LDAPAttribute)attrEnum.nextElement();
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 netscape.ldap.LDAPAttribute
*/
public LDAPAttribute getAttribute( String attrName ) {
prepareHashtable();
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;
}
}
/**
* Prepare hashtable for fast attribute lookups
*/
private void prepareHashtable() {
if ((attrHash == null) && (attrs.length >= ATTR_COUNT_REQUIRES_HASH)) {
attrHash = new Hashtable();
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 the <CODE>cn;lang-ja;phonetic</CODE> attribute 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 netscape.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;
}
/**
* Returns the attribute at the position specified by the index
* (for example, if you specify the index 0, the method returns the
* first attribute in the set). The index is 0-based.
*
* @param index Index of the attribute that you want to get.
* @return Attribute at the position specified by the index.
*/
public LDAPAttribute elementAt (int index) {
return attrs[index];
}
/**
* Removes attribute at the position specified by the index
* (for example, if you specify the index 0, the method removes the
* first attribute in the set). The index is 0-based.
*
* @param index Index of the attribute that you want to remove.
*/
public void removeElementAt (int index) {
if ((index >= 0) && (index < attrs.length)) {
synchronized(this) {
LDAPAttribute[] vals = new LDAPAttribute[attrs.length-1];
int j = 0;
for (int i = 0; i < attrs.length; i++) {
if (i != index) {
vals[j++] = attrs[i];
}
}
attrs = vals;
}
}
}
/**
* Returns the number of attributes in this set.
* @return Number of attributes in this attribute set.
*/
public int size () {
return attrs.length;
}
/**
* Adds the specified attribute to this attribute set.
* @param attr Attribute that you want to add to this set.
*/
public synchronized void add( LDAPAttribute attr ) {
if (attr != null) {
LDAPAttribute[] vals = new LDAPAttribute[attrs.length+1];
for (int i = 0; i < attrs.length; i++)
vals[i] = attrs[i];
vals[attrs.length] = attr;
attrs = vals;
if (attrHash != null) {
attrHash.put( attr.getName().toLowerCase(), attr );
}
}
}
/**
* Removes the specified attribute from the set.
* @param name Name of the attribute that you want removed.
*/
public synchronized void remove( String name ) {
for( int i = 0; i < attrs.length; i++ ) {
if ( name.equalsIgnoreCase( attrs[i].getName() ) ) {
removeElementAt(i);
break;
}
}
}
/**
* 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,43 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
/**
* Used to do explicit bind processing on a referral. A client may
* specify an instance of this class to be used on a single operation
* (through the <CODE>LDAPConstraints</CODE> object) or for all operations
* (through <CODE>LDAPConnection.setOption()</CODE>). It is typically used
* to control the authentication mechanism used on implicit referral
* handling.
*/
public interface LDAPBind {
/**
* This method is called by <CODE>LDAPConnection</CODE> when
* authenticating. An implementation may access the host, port,
* credentials, and other information in the <CODE>LDAPConnection</CODE>
* to decide on an appropriate authentication mechanism, and/or may
* interact with a user or external module.
* @exception netscape.ldap.LDAPException
* @see netscape.ldap.LDAPConnection#bind
* @param conn An established connection to an LDAP server.
*/
public void bind(LDAPConnection conn) throws LDAPException;
}

View File

@@ -0,0 +1,797 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import java.util.*;
import java.io.*;
import netscape.ldap.client.*;
import netscape.ldap.util.*;
import java.util.zip.CRC32;
/**
* <CODE>LDAPCache</CODE> is the class that 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 8
* 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>
*
* 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 netscape.ldap.LDAPConnection#setCache(netscape.ldap.LDAPCache)
* @see netscape.ldap.LDAPConnection#getCache
*/
public class LDAPCache implements TimerEventListener {
private Hashtable m_cache;
private long m_timeToLive;
private long m_maxSize;
private String[] m_dns;
private Vector m_orderedStruct;
private long m_remainingSize = 0;
/**
* Delimiter used internally when creating keys
* for the cache.
*/
public static final String DELIM = "#";
private Timer m_timer = null;
private static long TIMEOUT = 60000;
private long m_totalOpers = 0;
private static final boolean m_debug = false;
private long m_hits = 0;
private long m_flushes = 0;
/**
* 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>LDAPv2.SCOPE_BASE</CODE> (to remove the entry identified
* by <CODE>dn</CODE>)
* <LI><CODE>LDAPv2.SCOPE_ONE</CODE> (to remove the entries that
* have <CODE>dn</CODE> as their parent entry)
* <LI><CODE>LDAPv2.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,
* or <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();
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);
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;
}
}
m_cache.remove(key);
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 invoked when the timer expires.
* @param e The timer event containing the timer itself.
*/
public void timerExpired(TimerEvent e)
{
flushEntries();
Timer t = (Timer)e.getSource();
t.start();
}
/**
* 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;
LDAPControl[] clientControls = null;
// get server and client controls
if (cons != null)
{
serverControls = cons.getServerControls();
clientControls = cons.getClientControls();
}
if ((serverControls != null) && (serverControls.length > 0))
{
String[] objID = new String[serverControls.length];
for (int i=0; i<serverControls.length; i++) {
long val = getCRC32(serverControls[i].getValue());
objID[i] = new Long(val).toString();
}
key = key + appendString(objID);
}
else
key = key+appendString(0);
if ((clientControls != null) && (clientControls.length > 0))
{
String[] objID = new String[clientControls.length];
for (int i=0; i<clientControls.length; i++) {
long val = getCRC32(clientControls[i].getValue());
objID[i] = new Long(val).toString();
}
key = key + appendString(objID);
}
else
key = key+appendString(0);
long val = getCRC32(key.getBytes());
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 stays longer or equal to the time-to-live.
*/
synchronized void flushEntries()
{
Vector v = null;
boolean delete = false;
Date date = new Date();
long currTime = date.getTime();
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 = 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.
* @exception LDAPException Get thrown when failed to add the entry.
*/
synchronized void addEntry(Long key, Object value) throws LDAPException
{
// if entry exists, dont perform add operation
if (m_cache.get(key) != null)
return;
Vector v = (Vector)value;
// assume the size of the key is 4 bytes
long size = ((Long)v.elementAt(0)).longValue()+4;
if (size > m_maxSize) {
throw new LDAPException("Failed to add an entry to the cache since the new entry exceeds the cache size", LDAPException.OTHER);
}
v.setElementAt(new Long(size), 0);
// 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 = m_remainingSize +
((Long)val.elementAt(0)).longValue();
if (m_remainingSize >= size)
break;
}
}
m_remainingSize = m_remainingSize - size;
m_cache.put(key, v);
Vector element = new Vector();
element.addElement(key);
Date date = new Date();
element.addElement(new Long(date.getTime()));
m_orderedStruct.addElement(element);
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());
}
}
/**
* Gets the number of entries being cached.
* @return The number of entries being cached.
*/
int size()
{
return m_cache.size();
}
/**
* Clean up
*/
void cleanup() {
m_timer.stop();
}
/**
* 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();
m_timer = new Timer(TIMEOUT);
m_timer.addTimerExpiredEventListener((TimerEventListener)this);
m_timer.start();
}
/**
* Concatenate the specified integer with the delimiter.
* @param str The string which concatenate with the delimiter.
* @return The concatenated string
*/
private String appendString(String str) {
if (str == null)
return "null"+DELIM;
else
return str.trim()+DELIM;
}
/**
* Concatenate the specified integer with the delimiter.
* @param num The integer which 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 string being sorted. 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) {
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. It also provides
* methods to register/deregister the event listeners.
*/
class Timer {
private long m_timeout;
private Thread t = null;
private TimerEventListener listener;
protected TimerEventListener stopListener = null;
/**
* Constructor with the specified timout.
* @param timeout The timeout value in milliseconds.
*/
Timer(long timeout) {
m_timeout = timeout;
}
/**
* Start the timer.
*/
void start() {
TimerRunnable trun = new TimerRunnable(this);
t = new Thread(trun);
t.start();
}
/**
* Stop the timer.
*/
void stop() {
t.interrupt();
}
/**
* Get the timeout value.
* @return the timeout value.
*/
long getTimeout() {
return m_timeout;
}
/**
* Notify the listener when the timer expires.
*/
void fireExpiredEvent() {
TimerEvent event;
if (stopListener != null)
{
event = new TimerEvent(this);
stopListener.timerExpired(event);
}
}
/**
* Add the listener to the queue who wants to be notified when the timer
* expires.
*/
void addTimerExpiredEventListener(TimerEventListener listener) {
stopListener = listener;
}
/**
* Remove the listener from the queue who will not get notified when the
* timer expires.
*/
void removeTimerExpiredEventListener(TimerEventListener listener) {
stopListener = null;
}
}
/**
* Represents the starting point for the timer thread to execute.
*/
class TimerRunnable implements Runnable {
Timer m_timer;
/**
* Constructor with the specified timer object.
* @param t The timer
*/
TimerRunnable(Timer t) {
m_timer = t;
}
/**
* 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_timer.getTimeout());
} catch (InterruptedException e) {
// This happens if the timer is stopped
}
}
m_timer.fireExpiredEvent();
}
}
/**
* Represents the timer event. When the timer expires, it will notify
* all the registered listeners which receive the timer event. The
* listener can retrieve the source of the event from the timer event.
*/
class TimerEvent extends EventObject {
/**
* Constructor with the specified source of the timer event.
* @param source The source of the timer event.
*/
TimerEvent(Object source) {
super(source);
}
}
/**
* The timer client needs to implement this interface if it wants to
* receive the timeout event.
*/
interface TimerEventListener extends EventListener {
/**
* Gets invoked when the timer expires.
* @param timeout Timeout event contains the source of the event which is
* the timer.
*/
void timerExpired(TimerEvent timeout);
}

View File

@@ -0,0 +1,61 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
/**
* This static class checks if the caller is the applet running in the
* communicator. If so, then it returns the appropriate method.
*/
class LDAPCheckComm {
/**
* It 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 it the method is not found or
* the caller is not an applet running in the 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,277 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import java.util.*;
import java.text.*;
import netscape.ldap.client.*;
/**
* 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 LDAPEntryComparator
* @see LDAPSearchResults#sort
*/
public class LDAPCompareAttrNames implements LDAPEntryComparator {
String m_attrs[];
boolean m_ascending[];
Locale m_locale = null;
Collator m_collator = null;
/**
* 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) {
m_attrs = new String[1];
m_attrs[0] = attribute;
m_ascending = new boolean[1];
m_ascending[0] = true;
}
/**
* Constructs a comparator that compares the string values in
* 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) {
m_attrs = new String[1];
m_attrs[0] = attribute;
m_ascending = new boolean[1];
m_ascending[0] = ascendingFlag;
}
/**
* Constructs a comparator that compares the string values in
* 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
* that you want 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 the <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) {
m_attrs = attributes;
m_ascending = new boolean[attributes.length];
for( int i = 0; i < attributes.length; i++ )
m_ascending[i] = true;
}
/**
* Constructs a comparator that compares the string values in
* a set of named attributes in LDAP entries and that allows you
* to sort the entries in ascending or descending order.
* <P>
*
* Use an array of strings to specify the set of attributes
* that you want 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>, sort the attributes in ascending order.
*/
public LDAPCompareAttrNames (String[] attributes,
boolean[] ascendingFlags) {
m_attrs = attributes;
m_ascending = ascendingFlags;
if ( m_ascending == null ) {
m_ascending = new boolean[attributes.length];
for( int i = 0; i < attributes.length; i++ )
m_ascending[i] = true;
}
}
/**
* Get the locale used for collation, if any. If it is null,
* an ordinary string comparison will be used for sorting.
*
* @return The locale used for collation, or null.
*/
public Locale getLocale() {
return m_locale;
}
/**
* Set the locale used for collation, if any. If it is null,
* an ordinary string comparison will be used for sorting.
*
* @param locale The locale used for collation, or null.
*/
public void setLocale( Locale locale ) {
m_locale = locale;
if ( m_locale == null ) {
m_collator = null;
} else {
m_collator = Collator.getInstance( m_locale );
}
}
/**
* If the value of the attribute in the first entry is greater
* than the attribute in the second entry, returns <CODE>true</CODE>.
* <P>
*
* If one of the entries is missing the attribute, the other is
* considered greater. By default, the first entry is greater.
* <P>
*
* If either entry contains multiple values, only the first value
* is used for comparisons.
* <P>
*
* @param greater Entry to be tested against.
* @param less Entry to test.
* @return <CODE>true</CODE> if (<CODE>greater &gt; less</CODE>).
*/
public boolean isGreater (LDAPEntry greater, LDAPEntry less) {
if (greater.equals (less)) return false;
return attrGreater (greater, less, 0);
}
/**
* Compares a particular attribute in both entries. If equal,
* moves on to the next.
* @param greater Greater arg from isGreater
* @param less Less param is isGreater
* @param attrPos Index into array of attributes, indicating
* the attribute to compare
* @return (greater > less)
*/
boolean attrGreater (LDAPEntry greater, LDAPEntry less,
int attrPos) {
Enumeration greaterAttrSet =
greater.getAttributeSet().getAttributes();
Enumeration lessAttrSet =
less.getAttributeSet().getAttributes();
String greaterValue = null;
String lessValue = null;
String attrName = m_attrs[attrPos];
boolean ascending = m_ascending[attrPos];
try {
while (lessAttrSet.hasMoreElements()) {
LDAPAttribute currAttr =
(LDAPAttribute)(lessAttrSet.nextElement());
if (!attrName.equalsIgnoreCase (currAttr.getName()))
continue;
lessValue =
(String)(currAttr.getStringValues().nextElement());
break;
}
while (greaterAttrSet.hasMoreElements()) {
LDAPAttribute currAttr =
(LDAPAttribute)(greaterAttrSet.nextElement());
if (!attrName.equalsIgnoreCase (currAttr.getName()))
continue;
greaterValue =
(String)(currAttr.getStringValues().nextElement());
break;
}
}
catch (ClassCastException cce) {
// i.e. one of the enumerations did not contain the
// right type !?
return false;
}
catch (NoSuchElementException nse) {
// i.e. one of the attributes had no values !?
return false;
}
if ((lessValue == null) ^ (greaterValue == null))
return greaterValue != null;
if (lessValue == null ||
lessValue.equalsIgnoreCase (greaterValue))
if (attrPos == m_attrs.length - 1)
return false;
else
return attrGreater (greater, less, attrPos+1);
if ( m_collator != null ) {
if ( ascending )
return ( m_collator.compare( greaterValue, lessValue ) > 0 );
else
return ( m_collator.compare( greaterValue, lessValue ) < 0 );
} else {
if ( ascending )
return (greaterValue.compareTo (lessValue) > 0);
else
return (greaterValue.compareTo (lessValue) < 0);
}
}
}

View File

@@ -0,0 +1,408 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import java.util.*;
import java.io.*;
import java.net.*;
/**
* Make 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.
* 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{
/**
* 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 FAILED = 3;
/**
* 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 m_socket = null;
/**
* Last exception occured during connection setup
*/
private LDAPException m_connException = null;
/**
* List of server to use for the connection setup
*/
ServerEntry[] m_dsList;
/**
* Index of the last connected server
*/
private int m_dsIdx = -1;
/**
* Socket factory for SSL connections
*/
LDAPSocketFactory m_factory;
/**
* Connection setup policy (PARALLEL or SERIAL)
*/
int m_policy;
/**
* Delay in ms before another connection setup thread is started.
*/
int m_connSetupDelay;
/**
* Constructor
* @param host List of host names to connect to
* @param port List of port numbers corresponding to the host list
* @param factory Socket factory for SSL connections
* @param delay 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
*/
LDAPConnSetupMgr(String[] hosts, int[] ports, LDAPSocketFactory factory, int delay) {
m_dsList = new ServerEntry[hosts.length];
for (int i=0; i < hosts.length; i++) {
m_dsList[i] = new ServerEntry(hosts[i], ports[i], NEVER_USED);
}
m_factory = factory;
m_policy = (delay < 0) ? SERIAL : PARALLEL;
m_connSetupDelay = delay*1000;
}
/**
* Constructor used by clone()
*/
private LDAPConnSetupMgr() {}
/**
* Try to open the connection to any of the servers in the list.
*/
Socket openConnection() throws LDAPException{
m_socket = null;
m_connException = null;
// If reconnecting, sort dsList so that servers more likly to
// be available are tried first
sortDsList();
if (m_policy == SERIAL || m_dsList.length == 1) {
openSerial();
}
else {
openParallel();
}
if (m_socket != null) {
return m_socket;
}
if (m_connException != null) {
throw m_connException;
}
return null;
}
/**
* To be called when the current connection is lost.
* Put the connected server at the end of the server list for
* the next connect attempt.
*/
void invalidateConnection() {
if (m_socket != null) {
m_dsList[m_dsIdx].connSetupStatus = FAILED;
// Move the entry to the end of the list
int srvCnt = m_dsList.length, j=0;
ServerEntry[] newDsList = new ServerEntry[m_dsList.length];
for (int i=0; i < srvCnt; i++) {
if (i != m_dsIdx) {
newDsList[j++] = m_dsList[i];
}
}
newDsList[j] = m_dsList[m_dsIdx];
m_dsList = newDsList;
m_dsIdx = j;
}
m_socket = null;
}
/**
* To be 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 (m_socket != null) {
m_dsList[m_dsIdx].connSetupStatus = DISCONNECTED;
}
m_socket = null;
}
Socket getSocket() {
return m_socket;
}
String getHost() {
if (m_dsIdx >= 0) {
return m_dsList[m_dsIdx].host;
}
return m_dsList[0].host;
}
int getPort() {
if (m_dsIdx >= 0) {
return m_dsList[m_dsIdx].port;
}
return m_dsList[0].port;
}
/**
* Check if the user has voluntarily closed the connection
*/
boolean isUserDisconnected() {
return (m_dsIdx >=0 &&
m_dsList[m_dsIdx].connSetupStatus == DISCONNECTED);
}
/**
* Try sequentially to open a new connection to a server.
*/
private void openSerial() {
for (int i=0; i < m_dsList.length; i++) {
m_dsList[i].connSetupThread = Thread.currentThread();
connectServer(i);
if (m_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; m_socket==null && i < m_dsList.length; i++) {
//Create a Thread to execute connectSetver()
final int dsIdx = i;
String threadName = "ConnSetupMgr " +
m_dsList[dsIdx].host + ":" + m_dsList[dsIdx].port;
Thread t = new Thread(new Runnable() {
public void run() {
connectServer(dsIdx);
}
}, threadName);
m_dsList[dsIdx].connSetupThread = t;
t.setDaemon(true);
t.start();
// Wait before starting another thread if the delay is not zero
if (m_connSetupDelay != 0 && i < (m_dsList.length-1)) {
try {
wait(m_connSetupDelay);
}
catch (InterruptedException e) {}
}
}
// At this point all threads are started. Wait until first thread
// succeeds to connect or all threads terminate
while (m_socket == null) {
// Check whether there are still running threads
boolean threadsRunning = false;
for (int i=0; i < m_dsList.length; i++) {
if (m_dsList[i].connSetupThread != null) {
threadsRunning = true;
break;
}
}
if (!threadsRunning) { return; }
// Wait for a thread to terminate
try {
wait();
}
catch (InterruptedException e) {}
}
}
/**
* Connect to the server at the given index
*/
private void connectServer(int idx) {
ServerEntry entry = m_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 (m_factory == null) {
sock = new Socket (entry.host, entry.port);
//s.setSoLinger( false, -1 );
} else {
sock = m_factory.makeSocket(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 (m_socket == null && entry.connSetupThread == currThread) {
entry.connSetupThread = null;
if (sock != null) {
entry.connSetupStatus = CONNECTED;
m_socket = sock;
m_dsIdx = idx;
cleanup(); // Signal other concurrent threads to terminate
}
else {
entry.connSetupStatus = FAILED;
m_connException = conex;
}
notifyAll();
}
}
}
/**
* Terminate all concurrently running connection setup threads
*/
private synchronized void cleanup() {
Thread currThread = Thread.currentThread();
for (int i=0; i < m_dsList.length; i++) {
ServerEntry entry = m_dsList[i];
if (entry.connSetupThread != null && entry.connSetupThread != currThread) {
entry.connSetupStatus = FAILED;
//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;
}
}
}
/**
* Sort 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) connection setup failed/connection lost
*/
private void sortDsList() {
int srvCnt = m_dsList.length;
for (int i=1; i < srvCnt; i++) {
for (int j=0; j < i; j++) {
if (m_dsList[i].connSetupStatus < m_dsList[j].connSetupStatus) {
// swap entries
ServerEntry entry = m_dsList[j];
m_dsList[j] = m_dsList[i];
m_dsList[i] = entry;
}
}
}
}
public String toString() {
String str = "dsIdx="+m_dsIdx+ " dsList=";
for (int i=0; i < m_dsList.length; i++) {
str += m_dsList[i]+ " ";
}
return str;
}
public Object clone() {
LDAPConnSetupMgr cloneMgr = new LDAPConnSetupMgr();
cloneMgr.m_factory = m_factory;
cloneMgr.m_policy = m_policy;
cloneMgr.m_connSetupDelay = m_connSetupDelay;
cloneMgr.m_dsIdx = m_dsIdx;
cloneMgr.m_dsList = new ServerEntry[m_dsList.length];
cloneMgr.m_socket = m_socket;
for (int i=0; i<m_dsList.length; i++) {
ServerEntry e = m_dsList[i];
cloneMgr.m_dsList[i] = new ServerEntry(e.host, e.port, e.connSetupStatus);
}
return cloneMgr;
}
}

View File

@@ -0,0 +1,543 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import java.util.*;
import netscape.ldap.client.*;
import netscape.ldap.client.opers.*;
import netscape.ldap.ber.stream.*;
import netscape.ldap.util.*;
import java.io.*;
import java.net.*;
/**
* 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;
/**
* Internal variables
*/
transient private static int m_highMsgId;
transient private InputStream m_serverInput;
transient private OutputStream m_serverOutput;
transient private Hashtable m_requests;
transient private Hashtable m_messages = null;
transient private Vector m_registered;
transient private boolean m_disconnected = false;
transient private LDAPCache m_cache = null;
transient private boolean m_failed = false;
private Socket m_socket = null;
transient private Thread m_thread = null;
transient Object m_sendRequestLock = new Object();
transient LDAPConnSetupMgr m_connMgr = null;
/**
* Constructs a connection thread that maintains connection to the
* LDAP server.
* @param host LDAP host name
* @param port LDAP port number
* @param factory LDAP socket factory
*/
public LDAPConnThread(LDAPConnSetupMgr connMgr, LDAPCache cache)
throws LDAPException {
super("LDAPConnection " + connMgr.getHost() +":"+ connMgr.getPort());
m_requests = new Hashtable ();
m_registered = new Vector ();
m_connMgr = connMgr;
m_socket = connMgr.getSocket();
setCache( cache );
setDaemon(true);
try {
m_serverInput = new BufferedInputStream (m_socket.getInputStream());
m_serverOutput = new BufferedOutputStream (m_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, the stop
// method calls right away if the m_failed is set to true.
m_failed = true;
start();
throw new LDAPException ( "failed to connect to server " +
m_connMgr.getHost(), LDAPException.CONNECT_ERROR );
}
start(); /* start the thread */
}
InputStream getInputStream() {
return m_serverInput;
}
void setInputStream( InputStream is ) {
m_serverInput = is;
}
OutputStream getOutputStream() {
return m_serverOutput;
}
void setOutputStream( OutputStream os ) {
m_serverOutput = os;
}
/**
* 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 ) {
m_cache = cache;
m_messages = (m_cache != null) ? new Hashtable() : null;
}
/**
* Sends LDAP request via this connection thread.
* @param request request to send
* @param toNotify response listener to invoke when the response
* is ready
*/
synchronized void sendRequest (LDAPConnection conn, JDAPProtocolOp request,
LDAPMessageQueue toNotify, LDAPConstraints cons)
throws LDAPException {
if (m_serverOutput == null)
throw new LDAPException ( "not connected to a server",
LDAPException.SERVER_DOWN );
LDAPMessage msg =
new LDAPMessage(allocateId(), request, cons.getServerControls());
if ( toNotify != null ) {
if (!(request instanceof JDAPAbandonRequest ||
request instanceof JDAPUnbindRequest)) {
/* Only worry about toNotify if we expect a response... */
this.m_requests.put (new Integer (msg.getId()), toNotify);
/* Notify the backlog checker that there may be another outstanding
request */
resultRetrieved();
}
toNotify.addRequest(msg.getId(), conn, this);
}
synchronized( m_sendRequestLock ) {
try {
msg.write (m_serverOutput);
m_serverOutput.flush ();
} catch (IOException e) {
networkError(e);
}
}
}
/**
* Register with this connection thread.
* @param conn LDAP connection
*/
public synchronized void register(LDAPConnection conn) {
if (!m_registered.contains(conn))
m_registered.addElement(conn);
}
synchronized int getClientCount() {
return m_registered.size();
}
/**
* De-Register with this connection thread. If all the connection
* is deregistered. Then, this thread should be killed.
* @param conn LDAP connection
*/
public synchronized void deregister(LDAPConnection conn) {
m_registered.removeElement(conn);
if (m_registered.size() == 0) {
try {
LDAPConstraints cons = conn.getSearchConstraints();
sendRequest (null, new JDAPUnbindRequest (), null, cons);
cleanUp();
if ( m_thread != null ) {
m_thread.interrupt();
}
this.sleep(100); /* give enough time for threads to shutdown */
} catch (Exception e) {
LDAPConnection.printDebug(e.toString());
}
}
}
/**
* Clean ups before shutdown the thread.
*/
private void cleanUp() {
if (!m_disconnected) {
try {
m_serverOutput.close ();
} catch (Exception e) {
} finally {
m_serverOutput = null;
}
try {
m_serverInput.close ();
} catch (Exception e) {
} finally {
m_serverInput = null;
}
try {
m_socket.close ();
} catch (Exception e) {
} finally {
m_socket = null;
}
m_disconnected = true;
/**
* Notify the Connection Setup Manager that the connection was
* terminated by the user
*/
m_connMgr.disconnect();
/**
* Notify all the registered about this bad moment.
* IMPORTANT: This needs to be done at last. Otherwise, the socket
* input stream and output stream might never get closed and the whole
* task will get stuck in the stop method when we tried to stop the
* LDAPConnThread.
*/
if (m_registered != null) {
Vector registerCopy = (Vector)m_registered.clone();
Enumeration cancelled = registerCopy.elements();
while (cancelled.hasMoreElements ()) {
LDAPConnection c = (LDAPConnection)cancelled.nextElement();
c.deregisterConnection();
}
}
m_registered = null;
m_messages = null;
m_requests.clear();
}
}
/**
* Sleep if there is a backlog of search results
*/
private void checkBacklog() {
boolean doWait;
do {
doWait = false;
Enumeration listeners = m_requests.elements();
while( listeners.hasMoreElements() ) {
LDAPMessageQueue l =
(LDAPMessageQueue)listeners.nextElement();
// If there are any threads waiting for a regular response
// message, we have to go read the next incoming message
if ( !(l instanceof LDAPSearchListener) ) {
doWait = false;
break;
}
// If the backlog of any search thread is too great,
// wait for it to diminish, but if this is a synchronous
// search, then just keep reading
LDAPSearchListener sl = (LDAPSearchListener)l;
// Asynch operation ?
if (sl.isAsynchOp()) {
if (sl.getMessageCount() >= sl.getConstraints().getMaxBacklog()) {
doWait = true;
}
}
// synch op with non-zero batch size ?
else if (sl.getConstraints().getBatchSize() != 0) {
if (sl.getMessageCount() >= sl.getConstraints().getMaxBacklog()) {
doWait = true;
}
}
}
if ( doWait ) {
synchronized(this) {
try {
wait();
} catch (InterruptedException e ) {
}
}
}
} while ( doWait );
}
/**
* This is called when a search result has been retrieved from the incoming
* queue. We use the notification to unblock the listener 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 of establishing connection to the server,
// stop the thread right away...
if (m_failed) {
return;
}
m_thread = Thread.currentThread();
LDAPMessage msg = null;
JDAPBERTagDecoder decoder = new JDAPBERTagDecoder();
while (true) {
yield();
int[] nread = new int[1];
nread[0] = 0;
// Avoid too great a backlog of results
checkBacklog();
try {
if (m_thread.isInterrupted()) {
break;
}
BERElement element = BERElement.getElement(decoder,
m_serverInput,
nread);
msg = LDAPMessage.parseMessage(element);
// passed 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) {
networkError(e);
}
if (m_disconnected)
break;
}
}
/**
* Allocates a new LDAP message ID. These are arbitrary numbers used to
* correlate client requests with server responses.
* @return new unique msgId
*/
private synchronized int allocateId () {
m_highMsgId = (m_highMsgId + 1) % MAXMSGID;
return m_highMsgId;
}
/**
* 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 incoming New message from LDAP server
*/
private synchronized void processResponse (LDAPMessage incoming, int size) {
Integer messageID = new Integer (incoming.getId());
LDAPMessageQueue l = (LDAPMessageQueue)m_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 = incoming.getControls();
if (con != null) {
int msgid = incoming.getId();
LDAPConnection ldc = l.getConnection(msgid);
if (ldc != null) {
ldc.setResponseControls( this,
new LDAPResponseControl(ldc, msgid, con));
}
}
}
Vector v = null;
JDAPProtocolOp op = incoming.getProtocolOp ();
if ((op instanceof JDAPSearchResponse) ||
(op instanceof JDAPSearchResultReference)) {
l.addMessage (incoming);
Long key = ((LDAPSearchListener)l).getKey();
if ((m_cache != null) && (key != null)) {
// get the vector containing the LDAPMessages for the specified messageID
v = (Vector)m_messages.get(messageID);
if (v == null) {
v = new Vector();
// keeps track of the total size of all LDAPMessages belonging to the
// same messageID, now the size is 0
v.addElement(new Long(0));
}
// 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 LDAPEntry object gets stored in the cache
// instead of LDAPMessage object.
long entrySize = ((Long)v.firstElement()).longValue() + size;
// 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)incoming).getEntry());
// replace the entry
m_messages.put(messageID, v);
}
} else {
l.addMessage (incoming);
if (l instanceof LDAPSearchListener) {
Long key = ((LDAPSearchListener)l).getKey();
if (key != null) {
boolean fail = false;
JDAPProtocolOp protocolOp = incoming.getProtocolOp();
if (protocolOp instanceof JDAPSearchResult) {
JDAPResult res = (JDAPResult)protocolOp;
if (res.getResultCode() > 0) {
fail = true;
}
}
if ((!fail) && (m_cache != null)) {
// Collect all the LDAPMessages for the specified messageID
// no need to keep track of this entry. Remove it.
v = (Vector)m_messages.remove(messageID);
// If v is null, meaning there are no search results from the
// server
if (v == null) {
v = new Vector();
// set the entry size to be 0
v.addElement(new Long(0));
}
try {
// add the new entry with key and value (a vector of
// LDAPEntry objects)
m_cache.addEntry(key, v);
} catch (LDAPException e) {
System.out.println("Exception: "+e.toString());
}
}
}
}
m_requests.remove (messageID);
}
}
/**
* Stop dispatching responses for a particular message ID.
* @param id Message ID for which to discard responses.
*/
synchronized void abandon (int id ) {
LDAPMessageQueue l = (LDAPMessageQueue)m_requests.remove(new Integer(id));
if (l != null) {
l.removeRequest(id);
}
notifyAll(); // If LDAPConnThread is blocked in checkBacklog()
}
/**
* 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) {
try {
// notify the Connection Setup Manager that the connection is lost
m_connMgr.invalidateConnection();
// notify each listener that the server is down.
Enumeration requests = m_requests.elements();
while (requests.hasMoreElements()) {
LDAPMessageQueue listener =
(LDAPMessageQueue)requests.nextElement();
listener.setException(this, new LDAPException("Server down",
LDAPException.OTHER));
}
cleanUp();
} catch (NullPointerException ee) {
System.err.println("Exception: "+ee.toString());
}
/**
* Notify all the registered connections.
* 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 in the stop method when we try to stop the
* LDAPConnThread.
*/
if (m_registered != null) {
Vector registerCopy = (Vector)m_registered.clone();
Enumeration cancelled = registerCopy.elements();
while (cancelled.hasMoreElements ()) {
LDAPConnection c = (LDAPConnection)cancelled.nextElement();
c.deregisterConnection();
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,344 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
/**
* 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 {
private int m_hop_limit;
private LDAPBind m_bind_proc;
private LDAPRebind m_rebind_proc;
private boolean referrals;
private int m_time_limit;
private LDAPControl[] m_clientControls;
private LDAPControl[] m_serverControls;
/**
* Constructs an <CODE>LDAPConstraints</CODE> object that specifies
* the default set of constraints.
*/
public LDAPConstraints() {
m_time_limit = 0;
referrals = false;
m_bind_proc = null;
m_rebind_proc = null;
m_hop_limit = 5;
m_clientControls = null;
m_serverControls = null;
}
/**
* 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 rebind_proc Specifies the object that
* implements the <CODE>LDAPRebind</CODE> interface (you need to
* define this class). The object will be used when the client
* follows referrals automatically. The object provides the client
* with a method for getting the distinguished name and password
* used to authenticate to another LDAP server during a referral.
* (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 netscape.ldap.LDAPConnection#setOption(int, java.lang.Object)
*/
public LDAPConstraints( int msLimit, boolean doReferrals,
LDAPRebind rebind_proc, int hop_limit) {
m_time_limit = msLimit;
referrals = doReferrals;
m_bind_proc = null;
m_rebind_proc = rebind_proc;
m_hop_limit = hop_limit;
m_clientControls = null;
m_serverControls = null;
}
/**
* 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 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 netscape.ldap.LDAPConnection#setOption(int, java.lang.Object)
*/
public LDAPConstraints( int msLimit, boolean doReferrals,
LDAPBind bind_proc, int hop_limit) {
m_time_limit = msLimit;
referrals = doReferrals;
m_bind_proc = bind_proc;
m_rebind_proc = null;
m_hop_limit = hop_limit;
m_clientControls = null;
m_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 m_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 getReferrals() {
return referrals;
}
/**
* Returns the object that provides the mechanism for authenticating to the
* server on referrals. This object must implement the <CODE>LDAPBind</CODE>
* interface.
* @return Object to be used to authenticate to the server on referrals.
* @see netscape.ldap.LDAPBind
*/
public LDAPBind getBindProc() {
return m_bind_proc;
}
/**
* Returns the object that provides the method for getting
* authentication information. This object must
* implement the <CODE>LDAPRebind</CODE> interface.
* @return Object to be used to obtain information for
* authenticating to other LDAP servers during referrals.
* @see netscape.ldap.LDAPRebind
* @see netscape.ldap.LDAPRebindAuth
*/
public LDAPRebind getRebindProc() {
return m_rebind_proc;
}
/**
* 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 m_hop_limit;
}
/**
* Returns any client controls to be applied by the client
* to LDAP operations.
* @return Client controls to be applied by the client to LDAP operations.
* @see netscape.ldap.LDAPControl
* @see netscape.ldap.LDAPConnection#getOption
* @see netscape.ldap.LDAPConnection#setOption
*/
public LDAPControl[] getClientControls() {
return m_clientControls;
}
/**
* Returns any server controls to be applied by the server
* to LDAP operations.
* @return Server controls to be applied by the server to LDAP operations.
* @see netscape.ldap.LDAPControl
* @see netscape.ldap.LDAPConnection#getOption
* @see netscape.ldap.LDAPConnection#setOption
*/
public LDAPControl[] getServerControls() {
return m_serverControls;
}
/**
* 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.
* @param msLimit Maximum number of milliseconds to wait for operation
* results.
* (0 by default, which means that there is no maximum time limit.)
*/
public void setTimeLimit( int msLimit ) {
m_time_limit = msLimit;
}
/**
* 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>.
* (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>LDAPRebind</CODE> or
* <CODE>LDAPBind</CODE> interface. The <CODE>LDAPRebind</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>setRebindProc</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>setBindProc</BIND> 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 netscape.ldap.LDAPBind
* @see netscape.ldap.LDAPRebind
* @see netscape.ldap.LDAPRebindAuth
*/
public void setReferrals( boolean doReferrals ) {
referrals = doReferrals;
}
/**
* Sets the object that provides the mechanism for authenticating
* to the server on referrals. This object must implement
* the <CODE>LDAPBind</CODE> interface.(By default, this is
* <CODE>null</CODE>.) This method sets the <CODE>LDAPRebind</CODE>
* object to null for this constraint.
* @param bind_proc Object to be used to authenticate to the server
* on referrals.
* @see netscape.ldap.LDAPBind
*/
public void setBindProc( LDAPBind bind_proc ) {
m_bind_proc = bind_proc;
if (bind_proc != null) {
m_rebind_proc = null;
}
}
/**
* Specifies the object that provides the method for getting
* authentication information. This object must belong to a class
* that implements the <CODE>LDAPRebind</CODE> interface.
* (By default, this is <CODE>null</CODE>.) This method sets the
* <CODE>LDAPBind</CODE> object to null for this constraint.
* @param rebind_proc Object to be used to obtain information for
* authenticating to other LDAP servers during referrals.
*/
public void setRebindProc( LDAPRebind rebind_proc ) {
m_rebind_proc = rebind_proc;
if (rebind_proc != null) {
m_bind_proc = null;
}
}
/**
* 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 ) {
m_hop_limit = hop_limit;
}
/**
* Sets a client control for LDAP operations.
* @param control Client control for LDAP operations.
* @see netscape.ldap.LDAPControl
*/
public void setClientControls( LDAPControl control ) {
m_clientControls = new LDAPControl[1];
m_clientControls[0] = control;
}
/**
* Sets an array of client controls for LDAP operations.
* @param controls Array of client controls for LDAP operations.
* @see netscape.ldap.LDAPControl
*/
public void setClientControls( LDAPControl[] controls ) {
m_clientControls = controls;
}
/**
* Sets a server control for LDAP operations.
* @param control Server control for LDAP operations.
* @see netscape.ldap.LDAPControl
*/
public void setServerControls( LDAPControl control ) {
m_serverControls = new LDAPControl[1];
m_serverControls[0] = control;
}
/**
* Sets an array of server controls for LDAP operations.
* @param controls An array of server controls for LDAP operations.
* @see netscape.ldap.LDAPControl
*/
public void setServerControls( LDAPControl[] controls ) {
m_serverControls = controls;
}
/**
* Makes a copy of an existing set of constraints.
* @returns A copy of an existing set of constraints.
*/
public Object clone() {
LDAPConstraints o = new LDAPConstraints();
o.m_time_limit = this.m_time_limit;
o.referrals = this.referrals;
o.m_bind_proc = this.m_bind_proc;
o.m_rebind_proc = this.m_rebind_proc;
o.m_hop_limit = this.m_hop_limit;
if ( (this.m_clientControls != null) &&
(this.m_clientControls.length > 0) ) {
o.m_clientControls = new LDAPControl[this.m_clientControls.length];
for( int i = 0; i < this.m_clientControls.length; i++ )
o.m_clientControls[i] =
(LDAPControl)this.m_clientControls[i].clone();
}
if ( (this.m_serverControls != null) &&
(this.m_serverControls.length > 0) ) {
o.m_serverControls = new LDAPControl[this.m_serverControls.length];
for( int i = 0; i < this.m_serverControls.length; i++ )
o.m_serverControls[i] =
(LDAPControl)this.m_serverControls[i].clone();
}
return o;
}
}

View File

@@ -0,0 +1,505 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
import netscape.ldap.ber.stream.*;
import netscape.ldap.client.*;
import netscape.ldap.util.*;
import netscape.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 netscape.ldap.LDAPv3#CLIENTCONTROLS
* @see netscape.ldap.LDAPv3#SERVERCONTROLS
* @see netscape.ldap.LDAPConnection#search(java.lang.String, int, java.lang.String, java.lang.String[], boolean)
* @see netscape.ldap.LDAPConnection#getOption
* @see netscape.ldap.LDAPConnection#setOption
* @see netscape.ldap.LDAPConnection#getResponseControls
* @see netscape.ldap.LDAPConstraints#getClientControls
* @see netscape.ldap.LDAPConstraints#getServerControls
* @see netscape.ldap.LDAPConstraints#setClientControls
* @see netscape.ldap.LDAPConstraints#setServerControls
*/
public class LDAPControl implements Cloneable {
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 netscape.ldap.LDAPConstraints#setClientControls
* @see netscape.ldap.LDAPConstraints#setServerControls
*/
public LDAPControl(String id,
boolean critical,
byte vals[]) {
m_oid = id;
m_critical = critical;
m_value = vals;
}
/**
* Gets the object ID (OID) of the control.
* @return Object ID (OID) of the control.
*/
public String getID() {
return m_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 m_critical;
}
/**
* Gets the data in the control.
* @return Returns the data in the control as a byte array.
*/
public byte[] getValue() {
return m_value;
}
/**
* Gets the ber representation of control.
* @return ber representation of control
*/
BERElement getBERElement() {
BERSequence seq = new BERSequence();
seq.addElement(new BEROctetString (m_oid));
seq.addElement(new BERBoolean (m_critical));
if ( (m_value == null) || (m_value.length < 1) )
seq.addElement(new BEROctetString ((byte[])null));
else {
seq.addElement(new BEROctetString (m_value, 0, m_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 netscape.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 (m_controlClassHash == null) {
m_controlClassHash = new Hashtable();
}
// 4. add the controlClass
m_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 netscape.ldap.LDAPControl#register
*
*/
protected static Class lookupControlClass(String oid) {
if (m_controlClassHash == null) {
return null;
}
return (Class)m_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 be instantiated.
* @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 netscape.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 netscape.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 A <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 netscape.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 ( m_value != null ) {
vals = new byte[m_value.length];
for( int i = 0; i < m_value.length; i++ )
vals[i] = m_value[i];
}
LDAPControl control = new LDAPControl( m_oid, m_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 ( m_value != null ) {
s += ' ' + LDIF.toPrintableString( m_value );
}
return "LDAPControl {" + s + '}';
}
private String m_oid;
protected boolean m_critical = false;
protected byte[] m_value = null;
static private Hashtable m_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,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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import java.util.*;
import netscape.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 distinguished name (DN).
* @param dn Distinguished name that you want to get the components of.
* @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 netscape.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 the individual components of a relative distinguished name (RDN).
* @param rdn Relative distinguished name that you want to get the components of.
* @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 netscape.ldap.LDAPDN#explodeDN(java.lang.String, boolean)
*/
public static String[] explodeRDN (String rdn, boolean noTypes) {
RDN name = new RDN(rdn);
return name.explodeRDN(noTypes);
}
/**
* Returns the RDN after escaping the characters specified
* by <CODE>netscape.ldap.util.DN.ESCAPED_CHAR</CODE>.
* <P>
*
* @param rdn The RDN that you want escaped.
* @return The RDN with the characters escaped.
* @see netscape.ldap.util.DN#ESCAPED_CHAR
* @see netscape.ldap.LDAPDN#unEscapeRDN(java.lang.String)
*/
public static String escapeRDN(String rdn) {
RDN name = new RDN(rdn);
String val = name.getValue();
if (val == null)
return rdn;
StringBuffer buffer = new StringBuffer(val);
int i=0;
while (i<buffer.length()) {
if (isEscape(buffer.charAt(i))) {
buffer.insert(i, '\\');
i++;
}
i++;
}
return name.getType()+"="+(new String(buffer));
}
/**
* Returns the RDN after unescaping any escaped characters.
* For a list of characters that are typically escaped in a
* DN, see <CODE>netscape.ldap.LDAPDN.ESCAPED_CHAR</CODE>.
* <P>
*
* @param rdn The RDN that you want unescaped.
* @return The unescaped RDN.
* @see netscape.ldap.util.DN#ESCAPED_CHAR
* @see netscape.ldap.LDAPDN#escapeRDN(java.lang.String)
*/
public static String unEscapeRDN(String rdn) {
RDN name = new RDN(rdn);
String val = name.getValue();
if (val == null)
return rdn;
StringBuffer buffer = new StringBuffer(val);
StringBuffer copy = new StringBuffer();
int i=0;
while (i<buffer.length()) {
char c = buffer.charAt(i);
if (c != '\\')
copy.append(c);
i++;
}
return name.getType()+"="+(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,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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import java.util.*;
/**
* Represents an entry in the directory.
*
* @version 1.0
*/
public class LDAPEntry {
private String dn = null;
private LDAPAttributeSet attrSet = null;
/**
* Constructs an empty entry.
*/
public LDAPEntry() {
dn = null;
attrSet = null;
}
/**
* 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 = null;
}
/**
* 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 that you want assigned to the new entry.
* @see netscape.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;
}
/**
* Returns the attribute set of the entry.
* @return Set of attributes in the entry.
* @see netscape.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 netscape.ldap.LDAPAttributeSet
* @see netscape.ldap.LDAPAttributeSet#getSubset
*/
public LDAPAttributeSet getAttributeSet(String subtype) {
return attrSet.getSubset(subtype);
}
/**
* 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 netscape.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 netscape.ldap.LDAPAttribute
*/
public LDAPAttribute getAttribute( String attrName, String lang ) {
return attrSet.getAttribute( attrName, lang );
}
/**
* 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();
}
}

View File

@@ -0,0 +1,62 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
/**
* The <CODE>LDAPEntryComparator</CODE> interface represents the
* algorithm used to sort the search results. This interface specifies
* one method, <CODE>isGreater</CODE>, which compares two entries and
* determines the order in which the two entries should be sorted.
* <P>
*
* The <CODE>netscape.ldap</CODE> package includes a class that
* implements this interface. The <CODE>LDAPCompareAttrNames</CODE>
* class represents a comparator that sorts the two entries alphabetically,
* based on the value of one or more attributes.
* <P>
*
* When calling the <CODE>sort</CODE> method of the
* <CODE>LDAPSearchResults</CODE> class, you need to specify
* a class that implements the <CODE>LDAPEntryComparator</CODE>
* interface.
* <P>
*
* @version 1.0
* @see netscape.ldap.LDAPCompareAttrNames
* @see netscape.ldap.LDAPSearchResults#sort
*/
public interface LDAPEntryComparator {
/**
* Specifies the algorithm used to
* compare entries when sorting search results.
* <P>
*
* <CODE>isGreater</CODE> returns <CODE>true</CODE>
* if the entry specified in the first argument should
* be sorted before the entry specified in the second
* argument.
* <P>
*
* @version 1.0
* @see netscape.ldap.LDAPCompareAttrNames
* @see netscape.ldap.LDAPSearchResults#sort
*/
public boolean isGreater (LDAPEntry greater, LDAPEntry less);
}

View File

@@ -0,0 +1,883 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import java.util.*;
import netscape.ldap.client.*;
import netscape.ldap.client.opers.*;
import java.io.*;
/**
* Indicates that an error has occurred. An <CODE>LDAPException</CODE>
* can result from physical problems (such as network errors) as well as
* problems with LDAP operations (for example, if the LDAP add operation
* fails because of duplicate entry).
* <P>
*
* Most errors that occur throw this type of exception. In order to determine
* the cause of the error, you can call the <CODE>getLDAPResultCode()</CODE>
* method to get the specific result code and compare this code against
* the result codes defined as fields in this class. (For example, if
* the result code matches the value of the field
* <CODE>LDAPException.TIME_LIMIT_EXCEEDED</CODE>, the time limit passed
* before the search operation could be completed.)
* <P>
*
* This exception includes methods for getting an error message that
* corresponds to the LDAP result code (for example, "Timelimit exceeded"
* for <CODE>LDAPException.TIME_LIMIT_EXCEEDED</CODE>). These error
* messages are specified in the following files:
* <PRE>netscape/ldap/errors/ErrorCodes_<I>locale_string</I>.props</PRE>
* where <I>locale_string</I> is the name of the locale that includes
* the language and country, but not the variant.
* <P>
*
* For example:
* <PRE>netscape/ldap/errors/ErrorCodes_en_US.props</PRE>
*
* The LDAP Java classes get this locale name by calling the
* <CODE>java.util.Locale.toString</CODE> method for the specified
* locale and ignoring the variant. If no locale is specified, the
* LDAP Java classes use the <CODE>java.util.Locale.getDefault</CODE>
* method to get the locale of the local host system.
* <P>
*
* In order to get error messages for different locales, you need to
* provide files containing the error messages for those locales.
* The files should be located in the <CODE>netscape/ldap/errors</CODE>
* directory and should use the naming convention specified above.
* <P>
*
* The following is a list of LDAP result codes:
* <PRE>
* Result
* Code Defined Value
* ====== =============
* 0 <A HREF="#SUCCESS">SUCCESS</A>
* 1 <A HREF="#OPERATION_ERROR">OPERATION_ERROR</A>
* 2 <A HREF="#PROTOCOL_ERROR">PROTOCOL_ERROR</A>
* 3 <A HREF="#TIME_LIMIT_EXCEEDED">TIME_LIMIT_EXCEEDED</A>
* 4 <A HREF="#SIZE_LIMIT_EXCEEDED">SIZE_LIMIT_EXCEEDED</A>
* 5 <A HREF="#COMPARE_FALSE">COMPARE_FALSE</A>
* 6 <A HREF="#COMPARE_TRUE">COMPARE_TRUE</A>
* 7 <A HREF="#AUTH_METHOD_NOT_SUPPORTED">AUTH_METHOD_NOT_SUPPORTED</A>
* 8 <A HREF="#STRONG_AUTH_REQUIRED">STRONG_AUTH_REQUIRED</A>
* 9 <A HREF="#LDAP_PARTIAL_RESULTS">LDAP_PARTIAL_RESULTS</A>
* 10 <A HREF="#REFERRAL">REFERRAL</A> (LDAP v3)
* 11 <A HREF="#ADMIN_LIMIT_EXCEEDED">ADMIN_LIMIT_EXCEEDED</A> (LDAP v3)
* 12 <A HREF="#UNAVAILABLE_CRITICAL_EXTENSION">UNAVAILABLE_CRITICAL_EXTENSION</A> (LDAP v3)
* 13 <A HREF="#CONFIDENTIALITY_REQUIRED">CONFIDENTIALITY_REQUIRED</A> (LDAP v3)
* 14 <A HREF="#SASL_BIND_IN_PROGRESS">SASL_BIND_IN_PROGRESS</A> (LDAP v3)
* 16 <A HREF="#NO_SUCH_ATTRIBUTE">NO_SUCH_ATTRIBUTE</A>
* 17 <A HREF="#UNDEFINED_ATTRIBUTE_TYPE">UNDEFINED_ATTRIBUTE_TYPE</A>
* 18 <A HREF="#INAPPROPRIATE_MATCHING">INAPPROPRIATE_MATCHING</A>
* 19 <A HREF="#CONSTRAINT_VIOLATION">CONSTRAINT_VIOLATION</A>
* 20 <A HREF="#ATTRIBUTE_OR_VALUE_EXISTS">ATTRIBUTE_OR_VALUE_EXISTS</A>
* 21 <A HREF="#INVALID_ATTRIBUTE_SYNTAX">INVALID_ATTRIBUTE_SYNTAX</A>
* 32 <A HREF="#NO_SUCH_OBJECT">NO_SUCH_OBJECT</A>
* 33 <A HREF="#ALIAS_PROBLEM">ALIAS_PROBLEM</A>
* 34 <A HREF="#INVALID_DN_SYNTAX">INVALID_DN_SYNTAX</A>
* 35 <A HREF="#IS_LEAF">IS_LEAF</A>
* 36 <A HREF="#ALIAS_DEREFERENCING_PROBLEM">ALIAS_DEREFERENCING_PROBLEM</A>
* 48 <A HREF="#INAPPROPRIATE_AUTHENTICATION">INAPPROPRIATE_AUTHENTICATION</A>
* 49 <A HREF="#INVALID_CREDENTIALS">INVALID_CREDENTIALS</A>
* 50 <A HREF="#INSUFFICIENT_ACCESS_RIGHTS">INSUFFICIENT_ACCESS_RIGHTS</A>
* 51 <A HREF="#BUSY">BUSY</A>
* 52 <A HREF="#UNAVAILABLE">UNAVAILABLE</A>
* 53 <A HREF="#UNWILLING_TO_PERFORM">UNWILLING_TO_PERFORM</A>
* 54 <A HREF="#LOOP_DETECT">LOOP_DETECT</A>
* 64 <A HREF="#NAMING_VIOLATION">NAMING_VIOLATION</A>
* 65 <A HREF="#OBJECT_CLASS_VIOLATION">OBJECT_CLASS_VIOLATION</A>
* 66 <A HREF="#NOT_ALLOWED_ON_NONLEAF">NOT_ALLOWED_ON_NONLEAF</A>
* 67 <A HREF="#NOT_ALLOWED_ON_RDN">NOT_ALLOWED_ON_RDN</A>
* 68 <A HREF="#ENTRY_ALREADY_EXISTS">ENTRY_ALREADY_EXISTS</A>
* 69 <A HREF="#OBJECT_CLASS_MODS_PROHIBITED">OBJECT_CLASS_MODS_PROHIBITED</A>
* 71 <A HREF="#AFFECTS_MULTIPLE_DSAS">AFFECTS_MULTIPLE_DSAS</A> (LDAP v3)
* 80 <A HREF="#OTHER">OTHER</A>
* 81 <A HREF="#SERVER_DOWN">SERVER_DOWN</A>
* 89 <A HREF="#PARAM_ERROR">PARAM_ERROR</A>
* 91 <A HREF="#CONNECT_ERROR">CONNECT_ERROR</A>
* 92 <A HREF="#LDAP_NOT_SUPPORTED">LDAP_NOT_SUPPORTED</A>
* 93 <A HREF="#CONTROL_NOT_FOUND">CONTROL_NOT_FOUND</A>
* 94 <A HREF="#NO_RESULTS_RETURNED">NO_RESULTS_RETURNED</A>
* 95 <A HREF="#MORE_RESULTS_TO_RETURN">MORE_RESULTS_TO_RETURN</A>
* 96 <A HREF="#CLIENT_LOOP">CLIENT_LOOP</A>
* 97 <A HREF="#REFERRAL_LIMIT_EXCEEDED">REFERRAL_LIMIT_EXCEEDED</A>
* </PRE>
* <P>
*
* @version 1.0
* @see netscape.ldap.LDAPReferralException
*/
public class LDAPException extends java.lang.Exception {
/**
* (0) The operation completed successfully.
*/
public final static int SUCCESS = 0;
/**
* (1) An internal error occurred in the LDAP server.
*/
public final static int OPERATION_ERROR = 1;
/**
* (2) A LDAP server could not correctly interpret the request
* sent by your client because the request does not strictly
* comply with the LDAP protocol. (For example, the data
* was not correctly BER-encoded, or a specified value -- such
* as the search scope or modification type -- does not
* comply with the LDAP protocol. If you invent your own
* search scope, for instance, this result code might be returned.<P>
*/
public final static int PROTOCOL_ERROR = 2;
/**
* (3) The search operation could not be completed within
* the maximum time limit. You can specify the maximum time
* limit by calling the <CODE>LDAPConnection.setOption</CODE>
* method or the <CODE>LDAPSearchConstraints.setServerTimeLimit</CODE>
* method.<P>
*
* @see netscape.ldap.LDAPConnection#setOption
* @see netscape.ldap.LDAPSearchConstraints#setServerTimeLimit
*/
public final static int TIME_LIMIT_EXCEEDED = 3;
/**
* (4) The search found more than the maximum number of results.
* You can specify the maximum number of results by calling the
* <CODE>LDAPConnection.setOption</CODE> method or the
* <CODE>LDAPSearchConstraints.setSizeLimit</CODE> method.<P>
*
* @see netscape.ldap.LDAPConnection#setOption
* @see netscape.ldap.LDAPSearchConstraints#setMaxResults
*/
public final static int SIZE_LIMIT_EXCEEDED = 4;
/**
* (5) Value returned by an LDAP compare operation if the
* specified attribute and value is not found in the entry
* (no matching value found).
*
* @see netscape.ldap.LDAPConnection#compare
*/
public final static int COMPARE_FALSE = 5;
/**
* (6) Value returned by an LDAP compare operation if the
* specified attribute and value is found in the entry
* (matching value found).
*
* @see netscape.ldap.LDAPConnection#compare
*/
public final static int COMPARE_TRUE = 6;
/**
* (7) The specified authentication method is not supported
* by the LDAP server that you are connecting to. The
* <CODE>LDAPConnection</CODE> class is implemented so that
* <CODE>LDAPConnection.authenticate</CODE> always
* uses the LDAP_AUTH_SIMPLE method of authentication.
* (<CODE>LDAPConnection.authenticate</CODE> does not
* allow you to select the method of authentication.)<P>
*/
public final static int AUTH_METHOD_NOT_SUPPORTED = 7;
/**
* (8) A stronger authentication method (more than LDAP_AUTH_SIMPLE)
* is required by the LDAP server that you are connecting to.
* The <CODE>LDAPConnection</CODE> class is implemented so that
* <CODE>LDAPConnection.authenticate</CODE> always
* uses the LDAP_AUTH_SIMPLE method of authentication.
* (<CODE>LDAPConnection.authenticate</CODE> does not
* allow you to select the method of authentication.)<P>
*/
public final static int STRONG_AUTH_REQUIRED = 8;
/**
* (9) The LDAP server is referring your client to another
* LDAP server. If you set up the <CODE>LDAPConnection</CODE>
* options or the <CODE>LDAPConstraints</CODE> options
* for automatic referral, your client will automatically
* connect and authenticate to the other LDAP server.
* (This <CODE>LDAPException</CODE> will not be raised.)
* <P>
*
* (To set up automatic referrals in an <CODE>LDAPConnection</CODE>
* object, set the <CODE>LDAPConnection.REFERRALS</CODE> option
* to <CODE>true</CODE> and the LDAPConnection.REFERRALS_REBIND_PROC</CODE>
* option to the object containing the method for retrieving
* authentication information (in other words, the distinguished
* name and password to use when authenticating to other LDAP servers).
* <P>
*
* If instead you set <CODE>LDAPConnection.REFERRALS</CODE>
* to <CODE>false</CODE> (or if you set
* <CODE>LDAPConstraints.setReferrals</CODE> to <CODE>false</CODE>,
* an <CODE>LDAPReferralException</CODE> is raised.
* <P>
*
* If an error occurs during the referral process, an
* <CODE>LDAPException</CODE> with this result code
* (<CODE>LDAP_PARTIAL_RESULTS</CODE>) is raised.
* <P>
*
* @see netscape.ldap.LDAPConnection#setOption
* @see netscape.ldap.LDAPConstraints#setReferrals
* @see netscape.ldap.LDAPConstraints#setRebindProc
* @see netscape.ldap.LDAPRebind
* @see netscape.ldap.LDAPRebindAuth
* @see netscape.ldap.LDAPReferralException
*/
public final static int LDAP_PARTIAL_RESULTS = 9;
/**
* (10) [LDAP v3] The server does not hold the requested entry.
* The referral field of the server's response contains a
* reference to another server (or set of servers), which
* your client can access through LDAP or other protocols.
* Typically, these references are LDAP URLs that identify
* the server that may contain the requested entry.
* <P>
*
* When this occurs, a <CODE>LDAPReferralException</CODE>
* is thrown. You can catch this exception and call the
* <CODE>getURLs</CODE> method to get the list of LDAP
* URLs from the exception.
* <P>
*
* @see netscape.ldap.LDAPReferralException
*/
public final static int REFERRAL = 10;
/**
* (11) [LDAP v3] The adminstrative limit on the
* maximum number of entries to return was exceeded.
* In the Netscape Directory Server 3.0, this
* corresponds to the "look through limit" for
* the server. This is the maximum number of
* entries that the server will check through
* when determining which entries match the
* search filter and scope.
* <P>
*/
public final static int ADMIN_LIMIT_EXCEEDED = 11;
/**
* (12) [LDAP v3] The server received an LDAP v3 control
* that is marked critical and either (1) is not
* recognized or supported by the server, or
* (2) is inappropriate for the operation requested.
* The Netscape Directory Server 3.0 also returns
* this result code if the client specifies a
* matching rule that is not supported by the server.
* <P>
*
* @see netscape.ldap.LDAPControl
*/
public final static int UNAVAILABLE_CRITICAL_EXTENSION = 12;
/**
* (13) [LDAP v3] A secure connection is required for
* this operation.
*/
public final static int CONFIDENTIALITY_REQUIRED = 13;
/**
* (14) [LDAP v3] While authenticating your client
* by using a SASL (Simple Authentication Security Layer)
* mechanism, the server requires the client to send
* a new SASL bind request (specifying the same SASL
* mechanism) to continue the authentication process.
*/
public final static int SASL_BIND_IN_PROGRESS = 14;
/**
* (16) The specified attribute could not be found.
*/
public final static int NO_SUCH_ATTRIBUTE = 16;
/**
* (17) The specified attribute is not defined.
*/
public final static int UNDEFINED_ATTRIBUTE_TYPE = 17;
/**
* (18) An inappropriate type of matching was used.
*/
public final static int INAPPROPRIATE_MATCHING = 18;
/**
* (19) An internal error occurred in the LDAP server.
*/
public final static int CONSTRAINT_VIOLATION = 19;
/**
* (20) The value that you are adding to an attribute
* already exists in the attribute.
*/
public final static int ATTRIBUTE_OR_VALUE_EXISTS = 20;
/**
* (21) The request contains invalid syntax.
*/
public final static int INVALID_ATTRIBUTE_SYNTAX = 21;
/**
* (32) The entry specified in the request does not exist.
*/
public final static int NO_SUCH_OBJECT = 32;
/**
* (33) An problem occurred with an alias.
*/
public final static int ALIAS_PROBLEM = 33;
/**
* (34) The specified distinguished name (DN) uses invalid syntax.
*/
public final static int INVALID_DN_SYNTAX = 34;
/**
* (35) The specified entry is a "leaf" entry (it has no entries
* beneath it in the directory tree).
*/
public final static int IS_LEAF = 35;
/**
* (36) An error occurred when dereferencing an alias.
*/
public final static int ALIAS_DEREFERENCING_PROBLEM = 36;
/**
* (48) The authentication presented to the server is inappropriate.
* This result code might occur, for example, if your client
* presents a password and the corresponding entry has no
* userpassword attribute.
*/
public final static int INAPPROPRIATE_AUTHENTICATION = 48;
/**
* (49) The credentials presented to the server for authentication
* are not valid. (For example, the password sent to the server
* does not match the user's password in the directory.)
*/
public final static int INVALID_CREDENTIALS = 49;
/**
* (50) The client is authenticated as a user who does not have the
* access privileges to perform this operation.
*/
public final static int INSUFFICIENT_ACCESS_RIGHTS = 50;
/**
* (51) The LDAP server is busy.
*/
public final static int BUSY = 51;
/**
* (52) The LDAP server is unavailable.
*/
public final static int UNAVAILABLE = 52;
/**
* (53) The LDAP server is unable to perform the specified operation.
*/
public final static int UNWILLING_TO_PERFORM = 53;
/**
* (54) A loop has been detected.
*/
public final static int LOOP_DETECT = 54;
/**
* (60) The "server-side sorting" control
* was not included with the "virtual list view"
* control in the search request.
*/
public final static int SORT_CONTROL_MISSING = 60;
/**
* (61) An index range error occurred.
*/
public final static int INDEX_RANGE_ERROR = 61;
/**
* (64) A naming violation has occurred.
*/
public final static int NAMING_VIOLATION = 64;
/**
* (65) The requested operation will add or change
* data so that the data no longer complies with
* the schema.
*/
public final static int OBJECT_CLASS_VIOLATION = 65;
/**
* (66) The requested operation can only be performed
* on an entry that has no entries beneath it in the
* directory tree (in other words, a "leaf" entry).
* <P>
*
* For example, you cannot delete or rename an entry
* if the entry has subentries beneath it.
* <P>
*/
public final static int NOT_ALLOWED_ON_NONLEAF = 66;
/**
* (67) The specified operation cannot be performed on
* a relative distinguished name (RDN).
*/
public final static int NOT_ALLOWED_ON_RDN = 67;
/**
* (68) The specified entry already exists. You might receive
* this error if, for example, you attempt to add an entry
* that already exists or if you attempt to change the name
* of an entry to the name of an entry that already exists.
*/
public final static int ENTRY_ALREADY_EXISTS = 68;
/**
* (69) You cannot modify the specified object class.
*/
public final static int OBJECT_CLASS_MODS_PROHIBITED = 69;
/**
* (71) [LDAP v3] The client attempted to move an entry
* from one LDAP server to another by requesting a "modify
* DN" operation. In general, clients should not be able
* to arbitrarily move entries and subtrees between servers.
* <P>
*
* @see netscape.ldap.LDAPConnection#rename(java.lang.String, java.lang.String, java.lang.String, boolean)
* @see netscape.ldap.LDAPConnection#rename(java.lang.String, java.lang.String, java.lang.String, boolean, LDAPConstraints)
*/
public final static int AFFECTS_MULTIPLE_DSAS = 71;
/**
* (80) General result code for other types of errors
* that may occur.
*/
public final static int OTHER = 80;
/**
* (81) The LDAP server cannot be contacted.
*/
public final static int SERVER_DOWN = 0x51;
/**
* (89) When calling a constructor or method from your client,
* one or more parameters were incorrectly specified.
*/
public final static int PARAM_ERROR = 0x59;
/**
* (91) Your LDAP client failed to connect to the LDAP server.
*/
public final static int CONNECT_ERROR = 0x5b;
/**
* (92) The request is not supported by this version of the LDAP protocol.
*/
public final static int LDAP_NOT_SUPPORTED = 0x5c;
/**
* (93) The requested control is not found.
* <P>
*
* @see netscape.ldap.LDAPControl
*/
public final static int CONTROL_NOT_FOUND = 0x5d;
/**
* (94) No results have been returned from the server.
*/
public final static int NO_RESULTS_RETURNED = 0x5e;
/**
* (95) More results are being returned from the server.
*/
public final static int MORE_RESULTS_TO_RETURN = 0x5f;
/**
* (96) Your LDAP client detected a loop in the referral.
*/
public final static int CLIENT_LOOP = 0x60;
/**
* (97) The number of sequential referrals (for example,
* the client may be referred first from LDAP server A to
* LDAP server B, then from LDAP server B to LDAP server C,
* and so on) has exceeded the maximum number of referrals
* (the <CODE>LDAPv2.REFERRALS_HOP_LIMIT</CODE> option).
* <P>
*
* @see netscape.ldap.LDAPv2#REFERRALS_HOP_LIMIT
* @see netscape.ldap.LDAPConnection#getOption
* @see netscape.ldap.LDAPConnection#setOption
*/
public final static int REFERRAL_LIMIT_EXCEEDED = 0x61;
/**
* Internal variables
*/
private int resultCode = -1;
private String errorMessage = null;
private String matchedDN = null;
private Locale m_locale = Locale.getDefault();
private static Hashtable cacheResource = new Hashtable();
private static final String baseName = "netscape/ldap/errors/ErrorCodes";
/**
* Constructs a default exception with no specific error information.
*/
public LDAPException() {
}
/**
* Constructs a default exception with a specified string of
* additional information. This string appears if you call
* the <CODE>toString()</CODE> method.
* <P>
*
* This form is used for lower-level errors.
* It is recommended that you always use one of the constructors
* that takes a result code as a parameter. (If your exception is
* thrown, any code that catches the exception may need to extract
* the result code from the exception.)
* <P>
* @param message The additional error information.
* @see netscape.ldap.LDAPException#toString()
*/
public LDAPException( String message ) {
super( message );
}
/**
* Constructs a default exception with a result code and
* a specified string of additional information. This string
* appears if you call the <CODE>toString()</CODE> method.
* The result code that you set is accessible through the
* <CODE>getLDAPResultCode()</CODE> method.
* <P>
*
* @param message The additional error information that you
* want to specify.
* @param resultCode The result code returned from the
* operation that caused this exception.
* @see netscape.ldap.LDAPException#toString()
* @see netscape.ldap.LDAPException#getLDAPResultCode()
*/
public LDAPException( String message, int resultCode ) {
super( message );
this.resultCode = resultCode;
}
/**
* Constructs a default exception with a result code, a specified
* string of additional information, and a string containing
* information passed back from the server.
* <P>
*
* After you construct the <CODE>LDAPException</CODE> object,
* the result code and messages will be accessible through the
* following ways:
* <P>
* <UL>
* <LI>The first 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>
*
* Use this form of the constructor
* for higher-level LDAP operational errors.
* @param message The additional error information that you
* want to specify.
* @param resultCode The result code returned from the
* operation that caused this exception.
* @param serverErrorMessage Error message specifying additional
* information returned from the server.
* @see netscape.ldap.LDAPException#toString()
* @see netscape.ldap.LDAPException#getLDAPResultCode()
* @see netscape.ldap.LDAPException#getLDAPErrorMessage()
*/
public LDAPException( String message, int resultCode,
String serverErrorMessage ) {
super( message );
this.resultCode = resultCode;
this.errorMessage = serverErrorMessage;
}
/**
* Constructs a default exception with a result code, a specified
* string of additional information, a string containing
* information passed back from the server, and the DN of the
* closest matching entry, if the exception was thrown because
* an entry could not be found (for example, if <CODE>cn=Babs Jensen,
* ou=People, c=Airius.com</CODE> could not be found but
* <CODE>ou=People, c=Airius.com</CODE> is a valid directory entry,
* the &quot;matched DN&quot; is <CODE>ou=People, c=Airius.com</CODE>.
* <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>
* <LI>The matched DN that you set is accessible through the
* <CODE>getMatchedDN</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 matchedDN Maximal subset of a specified DN which could be
* matched by the server.
* @see netscape.ldap.LDAPException#toString()
* @see netscape.ldap.LDAPException#getLDAPResultCode()
* @see netscape.ldap.LDAPException#getLDAPErrorMessage()
* @see netscape.ldap.LDAPException#getMatchedDN()
*/
public LDAPException( String message, int resultCode,
String serverErrorMessage, String matchedDN ) {
super( message );
this.resultCode = resultCode;
this.errorMessage = serverErrorMessage;
this.matchedDN = matchedDN;
}
/**
* Returns the result code from the last error that occurred.
* This result code is defined as a public final static int member
* of this class. Note that this value is not always valid.
* -1 indicates that the result code is invalid.
* @return The LDAP result code of the last operation.
*/
public int getLDAPResultCode () {
return resultCode;
}
/**
* Returns the error message from the last error, if this message
* is available (that is, if this message was set). If the message
* was not set, this method returns <CODE>null</CODE>.
* <P>
*
* Note that this message is rarely set. (In order to set this message,
* the code constructing this exception must have called the constructor
* <CODE>LDAPException(String, int, String)</CODE>. The last argument,
* which is additional error information returned from the server,
* is the string returned by <CODE>getLDAPErrorMessage</CODE>.
* <P>
*
* In most cases, if you want information about
* the error generated, you should call the <CODE>toString()</CODE>
* method instead.
* <P>
*
* @return The error message of the last error (or <CODE>null</CODE>
* if no message was set).
* @see netscape.ldap.LDAPException#toString()
*/
public String getLDAPErrorMessage () {
return errorMessage;
}
/**
* Returns the maximal subset of a DN which could be matched by the
* server, if the server returned one of the following errors:
* <UL>
* <LI><CODE>NO_SUCH_OBJECT</CODE>
* <LI><CODE>ALIAS_PROBLEM</CODE>
* <LI><CODE>INVALID_DN_SYNTAX</CODE>
* <LI><CODE>ALIAS_DEREFERENCING_PROBLEM</CODE>
* </UL>
* </PRE>
* For example, if the DN <CODE>cn=Babs Jensen, o=People, c=Airius.com</CODE>
* could not be found by the DN <CODE>o=People, c=Airius.com</CODE>
* could be found, the matched DN is
* <CODE>o=People, c=Airius.com</CODE>.
* <P>
*
* If the exception does not specify a matching DN,
* this method returns <CODE>null</CODE>.
* @return The maximal subset of a DN which could be matched,
* or <CODE>null</CODE> if the error is not one of the above.
*/
public String getMatchedDN () {
return matchedDN;
}
/**
* Gets the string representation of the exception, which
* includes the result code, the message sent back from
* the LDAP server, the portion of the DN that the server
* could find in the directory (if applicable), and the
* error message corresponding to this result code.
* <P>
*
* For example:
*
* <PRE>netscape.ldap.LDAPException: error result (32); server error message; matchedDN = ou=people,o=airius.com; No such object</PRE>
*
* In this example, <CODE>error result</CODE> is the string of
* additional information specified in the exception, <CODE>32</CODE> is
* the result code, <CODE>server error message</CODE> is the additional
* information from the server specified in the exception, the
* matched DN is <CODE>ou=people,o=airius.com</CODE>, and the error message
* corresponding to the result code <CODE>32</CODE> is <CODE>No such
* object</CODE>.
* <P>
*
* The error message corresponding to the error code can also be
* retrieved by using the <CODE>errorCodeToString</CODE> method.
* Note that this method can generate error messages specific to
* a current locale.
* <P>
*
* @return String representation of exception
* @see netscape.ldap.LDAPException#errorCodeToString(int)
*/
public String toString() {
String str = super.toString() + " (" + resultCode + ")" ;
if ( (errorMessage != null) && (errorMessage.length() > 0) )
str += "; " + errorMessage;
if ( (matchedDN != null) && (matchedDN.length() > 0) )
str += "; matchedDN = " + matchedDN;
String errorStr = null;
if (((errorStr = errorCodeToString(m_locale)) != null) &&
(errorStr.length() > 0))
str += "; " + errorStr;
return str;
}
/**
* Returns the error message describing the error code (for this
* exception). The error message is specific to the default locale
* for this system. (The LDAP Java classes determine the default
* locale by calling the <CODE>java.util.Locale.getDefault</CODE>
* method and retrieve the error messages from the following file:
* <PRE>netscape/ldap/error/ErrorCodes_<I>locale_name</I>.props</PRE>
* where <I>locale_name</I> is the language and country (concatenated
* and delimited by an underscore) of the default locale. For example:
* <PRE>netscape/ldap/error/ErrorCodes_en_US.props</PRE>
*
* @return The error message describing the error code for this
* exception in the default locale
*/
public String errorCodeToString() {
return errorCodeToString(resultCode, m_locale);
}
/**
* Returns the error message describing the error code for this
* exception. The error message for the specified locale is retrieved
* from the following file:
* <PRE>netscape/ldap/error/ErrorCodes_<I>locale_name</I>.props</PRE>
* where <I>locale_name</I> is the language and country (concatenated
* and delimited by an underscore) of the default locale. For example:
* <PRE>netscape/ldap/error/ErrorCodes_en_US.props</PRE>
*
* @param l The <CODE>java.util.Locale</CODE> object representing the
* locale of the error message that you want to retrieve.
* @return The error message describing the current error code
* in the specified locale.
*/
public String errorCodeToString(Locale l) {
return errorCodeToString(resultCode, l);
}
/**
* Returns the error message describing the specified error code.
* The error message is specific to the default locale
* for this system. (The LDAP Java classes determine the default
* locale by calling the <CODE>java.util.Locale.getDefault</CODE>
* method and retrieve the error messages from the following file:
* <PRE>netscape/ldap/error/ErrorCodes_<I>locale_name</I>.props</PRE>
* where <I>locale_name</I> is the language and country (concatenated
* and delimited by an underscore) of the default locale. For example:
* <PRE>netscape/ldap/error/ErrorCodes_en_US.props</PRE>
*
* @param code The error code that you want to get the
* corresponding error message for.
* @return Error message describing the specified error code for
* the default locale.
*/
public static String errorCodeToString(int code) {
return errorCodeToString(code, Locale.getDefault());
}
/**
* Returns the error message describing the specified error code.
* The error message for the specified locale is retrieved from
* the following file:
* <PRE>netscape/ldap/error/ErrorCodes_<I>locale_name</I>.props</PRE>
* where <I>locale_name</I> is the language and country (concatenated
* and delimited by an underscore) of the default locale. For example:
* <PRE>netscape/ldap/error/ErrorCodes_en_US.props</PRE>
*
* @param code The error code that you want to get the
* corresponding error message for.
* @param locale The <CODE>java.util.Locale</CODE> object representing the
* locale of the error message that you want to retrieve.
* @return Error message describing the specified error code for
* the specified locale.
*/
public synchronized static String errorCodeToString(int code, Locale locale) {
try {
String localeStr = locale.toString();
PropertyResourceBundle p =
(PropertyResourceBundle)cacheResource.get(localeStr);
if (p == null) {
p = LDAPResourceBundle.getBundle(baseName);
if (p != null)
cacheResource.put(localeStr, p);
}
if (p != null) {
return (String)p.handleGetObject(Integer.toString(code));
}
} catch (IOException e) {
System.out.println("Cannot open resource file for LDAPException "+
baseName);
}
return null;
}
}

View File

@@ -0,0 +1,152 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
/**
* 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 netscape.ldap.LDAPConnection#extendedOperation(netscape.ldap.LDAPExtendedOperation)
* @see netscape.ldap.LDAPConnection#search(java.lang.String, int, java.lang.String, java.lang.String[], boolean)
*
*/
public class LDAPExtendedOperation {
/**
* Construct an object
* @param oid Identifier for the particular operation.
* @param vals Operation-specific data.
*/
public LDAPExtendedOperation( String oid, byte[] vals ) {
m_oid = oid;
m_vals = vals;
}
/**
* Get the identifier for this operation.
* @return oid Identifier for the particular operation.
*/
public String getID() {
return m_oid;
}
/**
* Get the data for this operation.
* @return vals Operation-specific data.
*/
public byte[] getValue() {
return m_vals;
}
private String m_oid;
private byte[] m_vals;
}

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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import netscape.ldap.client.opers.JDAPExtendedResponse;
/**
* Represents a server response to an extended operation request.
*
* @version 1.0
*/
public class LDAPExtendedResponse extends LDAPResponse {
/**
* Constructor
*
* @param msgid message identifier
* @param rsp Extended operation response
* @paarm controls Array of controls of null
*/
LDAPExtendedResponse(int msgid, JDAPExtendedResponse rsp, LDAPControl controls[]) {
super(msgid, rsp, controls);
}
/**
* Returns the OID of the response.
*
* @return The response OID
*/
public String getOID() {
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,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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.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 {
/**
* 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 netscape.ldap.LDAPInterruptedException#toString()
*/
LDAPInterruptedException( String message ) {
super( message, LDAPException.OTHER, null);
}
/**
* Gets the string representation of the exception.
*/
public String toString() {
String str = "netscape.ldap.LDAPInterruptedException: ";
String msg = super.getMessage();
if (msg != null) {
str +=msg;
}
return str;
}
}

View File

@@ -0,0 +1,298 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.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>
* 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>
* </PRE>
* <P>
* <CODE>LDAPMatchingRuleSchema</CODE> abstracts away from the two types and
* manages their relationships transparently.
*
* @version 1.0
* @see netscape.ldap.LDAPSchemaElement
**/
public class LDAPMatchingRuleSchema extends LDAPAttributeSchema {
/**
* Construct a matching rule definition, using the specified
* information.
* @param name Name of the matching rule.
* @param oid Object identifier (OID) of the matching rule
* in dotted-string 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 syntax Syntax of this matching rule. The value of this
* argument can be one of the following:
* <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)
* </UL>
*/
public LDAPMatchingRuleSchema( String name, String oid, String description,
String[] attributes, int syntax ) {
super( name, oid, description, syntax, true );
attrName = "matchingrules";
this.attributes = new String[attributes.length];
for( int i = 0; i < attributes.length; i++ )
this.attributes[i] = new String( attributes[i] );
}
/**
* 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";
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 ) {
syntaxString = val;
syntax = syntaxCheck( val );
}
}
/**
* Get the list of the OIDs of the attribute types which can be used
* with the matching rule. The list is a deep copy.
* @return Array of the OIDs of the attribute types which can be used
* with the matching rule.
*/
public String[] getAttributes() {
return attributes;
}
String getValue( boolean quotingBug ) {
String s = getValuePrefix();
s += "SYNTAX ";
if ( quotingBug ) {
s += '\'';
}
s += syntaxString;
if ( quotingBug ) {
s += '\'';
}
s += ' ';
String val = getCustomValues();
if ( val.length() > 0 ) {
s += val + ' ';
}
s += ')';
return s;
}
/**
* Get 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.
*/
public String getValue() {
return getValue( false );
}
/**
* Get 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();
s += "APPLIES ( ";
for( int i = 0; i < attributes.length; i++ ) {
if ( i > 0 )
s += " $ ";
s += attributes[i];
}
s += ") ";
String val = getCustomValues();
if ( val.length() > 0 ) {
s += val + ' ';
}
s += ')';
return s;
}
/**
* Add, remove or modify the definition from a Directory.
* @param ld An open connection to a Directory Server. Typically the
* connection must have been authenticated to add a definition.
* @param op Type of modification to make.
* @param name Name of attribute in the schema entry to modify. This
* is ignored here.
* @param dn The entry at which to update the schema.
* @exception LDAPException if the definition can't be added/removed.
*/
protected void update( LDAPConnection ld, int op, String name, String dn )
throws LDAPException {
LDAPAttribute[] attrs = new LDAPAttribute[2];
attrs[0] = new LDAPAttribute( "matchingRules",
getValue() );
/* Must update the matchingRuleUse value as well */
attrs[1] = new LDAPAttribute( "matchingRuleUse",
getUseValue() );
update( ld, op, attrs, dn );
}
/**
* Get the definition of the matching rule in a user friendly format.
* This is the format that the matching rule definition uses when
* you print the matching rule or the schema.
* @return Definition of the matching rule in a user friendly format.
*/
public String toString() {
String s = "Name: " + name + "; OID: " + oid + "; Type: ";
s += syntaxToString();
s += "; Description: " + description;
if ( attributes != null ) {
s += "; Applies to: ";
for( int i = 0; i < attributes.length; i++ ) {
if ( i > 0 )
s += ", ";
s += attributes[i];
}
}
s += getQualifierString( EXPLICIT );
return s;
}
private String[] attributes = null;
}

View File

@@ -0,0 +1,257 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import java.util.*;
import netscape.ldap.client.opers.*;
import netscape.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 {
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 m_msgid;
private JDAPProtocolOp m_protocolOp = null;
private LDAPControl m_controls[] = null;
/**
* Constructs a ldap message.
* @param msgid message identifier
* @param op operation protocol
*/
LDAPMessage(int msgid, JDAPProtocolOp op) {
m_msgid = msgid;
m_protocolOp = op;
}
LDAPMessage(int msgid, JDAPProtocolOp op, LDAPControl controls[]) {
m_msgid = msgid;
m_protocolOp = op;
m_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);
}
}
/**
* Returns the message identifer.
* @return message identifer
*/
public int getId(){
return m_msgid;
}
/**
* Returns the LDAP operation type of the message
* @return message type
*/
public int getType(){
return m_protocolOp.getType();
}
/**
* Retrieves the protocol operation.
* @return protocol operation
*/
JDAPProtocolOp getProtocolOp() {
return m_protocolOp;
}
/**
* Retrieves list of controls.
* @return controls
*/
public LDAPControl[] getControls() {
return m_controls;
}
/**
* Writes the ber encoding to stream.
* @param s output stream
*/
void write(OutputStream s) throws IOException {
BERSequence seq = new BERSequence();
BERInteger i = new BERInteger(m_msgid);
seq.addElement(i);
BERElement e = m_protocolOp.getBERElement();
if (e == null) {
throw new IOException("Bad BER element");
}
seq.addElement(e);
if (m_controls != null) { /* LDAPv3 additions */
BERSequence c = new BERSequence();
for (int j = 0; j < m_controls.length; j++) {
c.addElement(m_controls[j].getBERElement());
}
BERTag t = new BERTag(BERTag.CONTEXT|BERTag.CONSTRUCTED|0, c, true);
seq.addElement(t);
}
seq.write(s);
}
/**
* Returns string representation of a ldap message.
* @return ldap message
*/
public String toString() {
if (m_controls == null) {
return "[LDAPMessage] " + m_msgid + " " + m_protocolOp.toString();
}
else {
StringBuffer sb = new StringBuffer(
"[LDAPMessage] " + m_msgid + " " + m_protocolOp.toString());
for (int i =0; i < m_controls.length; i++) {
sb.append(" ctrl"+i+"=");
sb.append(m_controls[i].toString());
}
return sb.toString();
}
}
}

View File

@@ -0,0 +1,428 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
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.
*
* Superclass for LDAResponseListener and LDAPSearchListener
*
*/
class LDAPMessageQueue {
/**
* Request entry encapsulates request parameters
*/
private static class RequestEntry {
int id;
LDAPConnection connection;
LDAPConnThread connThread;
RequestEntry(int id, LDAPConnection connection, LDAPConnThread connThread) {
this.id= id;
this.connection = connection;
this.connThread = connThread;
}
}
/**
* Internal variables
*/
private /*LDAPMessage */ Vector m_messageQueue = new Vector(1);
private /*RequestEntry*/ Vector m_requestList = new Vector(1);
private LDAPException m_exception; /* For network errors */
private boolean m_asynchOp;
/**
* Constructor
* @param asynchOp A flag whether the object is used for asynchronous
* LDAP operations
* @see netscape.ldap.LDAPAsynchronousConnection
*/
LDAPMessageQueue (boolean asynchOp) {
m_asynchOp = asynchOp;
}
/**
* Returns a flag whether the listener is used for asynchronous LDAP
* operations
* @return Asynchronous operation flag
* @see netscape.ldap.LDAPAsynchronousConnection
*/
boolean isAsynchOp() {
return m_asynchOp;
}
/**
* 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 is no more outstanding requests
* @exception LDAPException Network error exception
* @exception LDAPInterruptedException The invoking thread was interrupted
*/
synchronized LDAPMessage nextMessage () throws LDAPException {
while(m_requestList.size() != 0 && m_exception == null && m_messageQueue.size() == 0) {
try {
wait ();
} catch (InterruptedException e) {
throw new LDAPInterruptedException("Interrupted LDAP operation");
}
}
// Network exception occurred ?
if (m_exception != null) {
LDAPException ex = m_exception;
m_exception = null;
throw ex;
}
// Are there any outstanding requests left
if (m_requestList.size() == 0) {
return null; // No outstanding requests
}
// Dequeue the first entry
LDAPMessage msg = (LDAPMessage) m_messageQueue.elementAt(0);
m_messageQueue.removeElementAt(0);
// Is the ldap operation completed?
if (msg instanceof LDAPResponse) {
removeRequest(msg.getId());
}
return msg;
}
/**
* Wait 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 is no more outstanding requests
* @exception LDAPException Network error exception
* @exception LDAPInterruptedException The invoking thread was interrupted
*/
synchronized LDAPResponse completeRequest () throws LDAPException {
while (true) {
while(m_requestList.size() != 0 && m_exception == null && m_messageQueue.size() == 0) {
try {
wait ();
} catch (InterruptedException e) {
throw new LDAPInterruptedException("Interrupted LDAP operation");
}
}
// Network exception occurred ?
if (m_exception != null) {
LDAPException ex = m_exception;
m_exception = null;
throw ex;
}
// Are there any outstanding requests left?
if (m_requestList.size() == 0) {
return null; // No outstanding requests
}
// Search an instance of LDAPResponse
for (int i= m_messageQueue.size()-1; i >=0; i--) {
LDAPMessage msg = (LDAPMessage) m_messageQueue.elementAt(i);
if (msg instanceof LDAPResponse) {
// Dequeue the entry and return
m_messageQueue.removeElementAt(i);
return (LDAPResponse)msg;
}
}
// Not found, wait for the next message
try {
wait ();
} catch (InterruptedException e) {
throw new LDAPInterruptedException("Interrupted LDAP operation");
}
}
}
/**
* 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.getIDs(), 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.getIDs().
* The proper way to handle this scenario is to create a separate listener
* for each new request, and after l.getIDs() has been invoked, merge the
* new request with the existing one.
* @param mq2 Message queue to be merged with this one.
*/
synchronized void merge(LDAPMessageQueue mq2) {
synchronized (mq2) {
for (int i=0; i < mq2.m_requestList.size(); i++) {
m_requestList.addElement(mq2.m_requestList.elementAt(i));
}
for (int i=0; i < mq2.m_messageQueue.size(); i++) {
m_messageQueue.addElement(mq2.m_messageQueue.elementAt(i));
}
if (mq2.m_exception != null) {
m_exception = mq2.m_exception;
}
mq2.reset();
notifyAll(); // notify for mq2
}
notifyAll(); // notify this mq
}
/**
* Retrieves all messages currently in the queue without blocking
* @returns Vector of messages
*/
synchronized Vector getAllMessages() {
Vector result = m_messageQueue;
m_messageQueue = new Vector(1);
return result;
}
/**
* Queues the LDAP server's response. This causes anyone waiting
* in nextMessage() to unblock.
* @param msg response message
*/
synchronized void addMessage (LDAPMessage msg) {
m_messageQueue.addElement(msg);
notifyAll ();
}
/**
* Signals that a network exception occured while servicing the
* request. This exception will be throw to any thread waiting
* in nextMessage()
* @param connThread LDAPConnThread on which the exception occurred
* @param e exception
*/
synchronized void setException (LDAPConnThread connThread, LDAPException e) {
m_exception = e;
removeAllRequests(connThread);
notifyAll ();
}
/**
* Checks if response message is received.
* @return true or false
*/
boolean isMessageReceived() {
return m_messageQueue.size() != 0;
}
/**
* Returns the count of queued messages
* @return message count
*/
public int getMessageCount () {
return m_messageQueue.size();
}
/**
* Remove all queued messages associated with the request ID
* Called when a LDAP operation is abandoned
*
* Not synchronized as its 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=(m_messageQueue.size()-1); i>=0; i--) {
LDAPMessage msg = (LDAPMessage)m_messageQueue.elementAt(i);
if (msg.getId() == id) {
m_messageQueue.removeElementAt(i);
removeCount++;
}
}
return removeCount;
}
/**
* Resets the state of this object, so it can be recycled.
* Used by LDAPConnection synchronous operations.
* @see netscape.ldap.LDAPConnection#getResponseListener
* @see netscape.ldap.LDAPConnection#getSearchListener
*/
void reset () {
m_exception = null;
m_messageQueue.removeAllElements();
m_requestList.removeAllElements();
}
/**
* Returns the connection associated with the specified request id
* @parm id request id
* @return connection
*/
synchronized LDAPConnection getConnection(int id) {
for (int i=0; i < m_requestList.size(); i++) {
RequestEntry entry = (RequestEntry)m_requestList.elementAt(i);
if (id == entry.id) {
return entry.connection;
}
}
return null;
}
/**
* Returns the connection thread associated with the specified request id
* @parm id request id
* @return connection thread
*/
synchronized LDAPConnThread getConnThread(int id) {
for (int i=0; i < m_requestList.size(); i++) {
RequestEntry entry = (RequestEntry)m_requestList.elementAt(i);
if (id == entry.id) {
return entry.connThread;
}
}
return null;
}
/**
* Returns message id of the last request
* @return Message id.
*/
synchronized int getID() {
int reqCnt = m_requestList.size();
if ( reqCnt == 0) {
return -1;
}
else {
RequestEntry entry = (RequestEntry)m_requestList.elementAt(reqCnt-1);
return entry.id;
}
}
/**
* Returns a list of message ids for all outstanding requests
* @return Message id array
*/
synchronized int[] getIDs() {
int[] ids = new int[m_requestList.size()];
for (int i=0; i < ids.length; i++) {
RequestEntry entry = (RequestEntry)m_requestList.elementAt(i);
ids[i] = entry.id;
}
return ids;
}
/**
* Registers a LDAP request
* @param id LDAP request message ID
* @param connection LDAP Connection for the message ID
* @param connThread A physical connection to the server
*/
synchronized void addRequest(int id, LDAPConnection connection,
LDAPConnThread connThread) {
m_requestList.addElement(new RequestEntry(id, connection, connThread));
}
/**
* Returns the number of outstanding requests.
* @return Outstanding request count.
*/
public int getRequestCount() {
return m_requestList.size();
}
/**
* Remove request with the specified ID
* Called when a LDAP operation is abandoned (called from
* LDAPConnThread), or terminated (called by nextMessage() when
* LDAPResponse message is received)
* @return Flag whether the request was removed
*/
synchronized boolean removeRequest(int id) {
for (int i=0; i < m_requestList.size(); i++) {
RequestEntry entry = (RequestEntry)m_requestList.elementAt(i);
if (id == entry.id) {
m_requestList.removeElementAt(i);
removeAllMessages(id);
notifyAll();
return true;
}
}
return false;
}
/**
* Remove all requests associated with the specified connThread
* Called when a connThread has a network error
* @return Number of removed request
*/
synchronized int removeAllRequests(LDAPConnThread connThread) {
int removeCount=0;
for (int i=(m_requestList.size()-1); i>=0; i--) {
RequestEntry entry = (RequestEntry)m_requestList.elementAt(i);
if (connThread == entry.connThread) {
m_requestList.removeElementAt(i);
removeCount++;
// remove all queued messages as well
removeAllMessages(entry.id);
}
}
notifyAll();
return removeCount;
}
/**
* String representation of the object
*/
public String toString() {
StringBuffer sb = new StringBuffer("LDAPMessageQueue:");
sb.append(" requestIDs={");
for (int i=0; i < m_requestList.size(); i++) {
if (i>0) {
sb.append(",");
}
sb.append(((RequestEntry)m_requestList.elementAt(i)).id);
}
sb.append("} messageCount="+m_messageQueue.size());
return sb.toString();
}
}

View File

@@ -0,0 +1,142 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import netscape.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 netscape.ldap.LDAPConnection#modify(java.lang.String, netscape.ldap.LDAPModification)
*/
public class LDAPModification {
/**
* 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, which 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 be modified.
* @see netscape.ldap.LDAPAttribute
*/
public LDAPModification( int op, LDAPAttribute attr ) {
operation = op;
attribute = attr;
}
/**
* 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;
}
/**
* Returns the attribute (possibly with values) to be modified.
* @return The attribute to be modified.
* @see netscape.ldap.LDAPAttribute
*/
public LDAPAttribute getAttribute() {
return attribute;
}
/**
* 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,135 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import java.util.*;
/**
* Represents a set of modifications to be made to attributes in an entry.
* A set of modifications is made up of <CODE>LDAPModification</CODE> objects.
* <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 netscape.ldap.LDAPModification
* @see netscape.ldap.LDAPConnection#modify(java.lang.String, netscape.ldap.LDAPModificationSet)
*/
public class LDAPModificationSet {
private int current = 0;
private Vector modifications;
/**
* Constructs a new, empty set of modifications.
* You can add modifications to this set by calling the
* <CODE>LDAPModificationsSet.add</CODE> method.
*/
public LDAPModificationSet() {
modifications = new Vector();
current = 0;
}
/**
* Retrieves the number of <CODE>LDAPModification</CODE>
* objects in this set.
* @return The number of <CODE>LDAPModification</CODE>
* objects in this set.
*/
public int size () {
return modifications.size();
}
/**
* Retrieves a particular <CODE>LDAPModification</CODE> object at
* the position specified by the index.
* @param Index position of the <CODE>LDAPModification</CODE>
* object that you want to retrieve.
* @return <CODE>LDAPModification</CODE> object representing
* a change to be made to an attribute.
*/
public LDAPModification elementAt (int index) {
return (LDAPModification)modifications.elementAt(index);
}
/**
* Removes a particular <CODE>LDAPModification</CODE> object at
* the position specified by the index.
* @param Index position of the <CODE>LDAPModification</CODE>
* object that you want to remove.
*/
public void removeElementAt( int index ) {
modifications.removeElementAt(index);
}
/**
* Specifies another modification to be added to the set of modifications.
* @param op The type of modification to make, which 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>
* If you are working with a binary value (not a string value), you need to bitwise OR (|) the
* modification type with <CODE>LDAPModification.BVALUES</CODE>.
* <P>
*
* @param attr The attribute (possibly with values) to be modified.
*/
public synchronized void add( int op, LDAPAttribute attr ) {
LDAPModification mod = new LDAPModification( op, attr );
modifications.addElement( mod );
}
/**
* Removes the first attribute with the specified name in the set of modifications.
* @param name Name of the attribute to be removed.
*/
public synchronized void remove( String name ) {
for( int i = 0; i < modifications.size(); i++ ) {
LDAPModification mod = (LDAPModification)modifications.elementAt( i );
LDAPAttribute attr = mod.getAttribute();
if ( name.equalsIgnoreCase( attr.getName() ) ) {
modifications.removeElementAt( i );
break;
}
}
}
/**
* Retrieves the string representation of the
* modification set.
*
* @return String representation of the modification set.
*/
public String toString() {
String s = "LDAPModificationSet: {";
for( int i = 0; i < modifications.size(); i++ ) {
s += (LDAPModification)modifications.elementAt(i);
if ( i < modifications.size()-1 ) {
s += ", ";
}
}
s += "}";
return s;
}
}

View File

@@ -0,0 +1,342 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.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 netscape.ldap.LDAPSchemaElement
**/
public class LDAPObjectClassSchema extends LDAPSchemaElement {
/**
* Constructs an object class definition, using the specified
* information.
* @param name Name 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 superior Name of the parent object class
* (the object class that the new object class inherits from).
* @param required Array of the names of the attributes required
* in this object class.
* @param optional Array of the names of the optional attributes
* allowed in this object class.
*/
public LDAPObjectClassSchema( String name, String oid, String superior,
String description,
String[] required, String[] optional ) {
super( name, oid, description );
attrName = "objectclasses";
this.superiors = new String[] { superior };
for( int i = 0; i < required.length; i++ ) {
must.addElement( required[i] );
}
for( int i = 0; i < optional.length; i++ ) {
may.addElement( optional[i] );
}
}
/**
* Constructs an object class definition, using the specified
* information.
* @param name Name 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 Name of parent object classes
* (the object class that the new object class inherits from).
* @param required Array of the names of the attributes required
* in this object class.
* @param optional Array of the names of the optional attributes
* allowed in this object class.
* @param type Either ABSTRACT, STRUCTURAL, or AUXILIARY
*/
public LDAPObjectClassSchema( String name, String oid,
String[] superiors,
String description,
String[] required, String[] optional,
int type ) {
this( name, oid, superiors[0], description, required, optional );
this.superiors = superiors;
this.type = type;
}
/**
* 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 );
String[] vals = getQualifier( SUPERIOR );
if ( vals != null ) {
superiors = vals;
setQualifier( SUPERIOR, (String)null );
}
if ( properties.containsKey( "AUXILIARY" ) ) {
type = AUXILIARY;
} else if ( properties.containsKey( "ABSTRACT" ) ) {
type = ABSTRACT;
} else if ( properties.containsKey( "STRUCTURAL" ) ) {
type = STRUCTURAL;
}
obsolete = properties.containsKey( OBSOLETE );
Vector v = (Vector)properties.get( "MAY" );
if ( v != null ) {
may = v;
}
v = (Vector)properties.get( "MUST" );
if ( v != null ) {
must = v;
}
}
/**
* Get the name of the object class that this class inherits from.
* @return The name of the object class that this class
* inherits from.
*/
public String getSuperior() {
return superiors[0];
}
/**
* Get 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 that this class
* inherits from.
*/
public String[] getSuperiors() {
return superiors;
}
/**
* Get an enumeration of the names of the required attribute for
* this object class.
* @return An enumeration of the names of the required attributes
* for this object class.
*/
public Enumeration getRequiredAttributes() {
return must.elements();
}
/**
* Get 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();
}
/**
* Get the type of the object class.
* @return STRUCTURAL, ABSTRACT, or AUXILIARY
*/
public int getType() {
return type;
}
/**
* 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();
s += getValue( SUPERIOR, quotingBug );
s += ' ';
String val = getOptionalValues( NOVALS );
if ( val.length() > 0 ) {
s += val + ' ';
}
s += getValue( "MUST", false );
s += ' ';
s += getValue( "MAY", false );
s += ' ';
val = getCustomValues();
if ( val.length() > 0 ) {
s += val + ' ';
}
s += ')';
return s;
}
/**
* Get the definition of the object class in a user friendly format.
* This is the format that the object class definition uses when
* you print the object class or the schema.
* @return Definition of the object class in a user friendly format.
*/
public String toString() {
String s = "Name: " + name + "; OID: " + oid +
"; Superior: ";
for( int i = 0; i < superiors.length; i++ ) {
s += superiors[i];
if ( i < (superiors.length-1) ) {
s += ", ";
}
}
s += "; Description: " + description + "; Required: ";
int i = 0;
Enumeration e = getRequiredAttributes();
while( e.hasMoreElements() ) {
if ( i > 0 )
s += ", ";
i++;
s += (String)e.nextElement();
}
s += "; Optional: ";
e = getOptionalAttributes();
i = 0;
while( e.hasMoreElements() ) {
if ( i > 0 )
s += ", ";
i++;
s += (String)e.nextElement();
}
switch ( type ) {
case STRUCTURAL:
break;
case ABSTRACT:
s += "; ABSTRACT";
break;
case AUXILIARY:
s += "; AUXILIARY";
break;
}
if ( obsolete ) {
s += "; OBSOLETE";
}
s += getQualifierString( IGNOREVALS );
return s;
}
public static final int STRUCTURAL = 0;
public static final int ABSTRACT = 1;
public static final int AUXILIARY = 2;
private String[] superiors = { "" };
private Vector must = new Vector();
private Vector may = new Vector();
private int type = STRUCTURAL;
// Qualifers known to not have values
static String[] NOVALS = { "ABSTRACT", "STRUCTURAL",
"AUXILIARY" };
static {
for( int i = 0; i < NOVALS.length; i++ ) {
novalsTable.put( NOVALS[i], NOVALS[i] );
}
}
static String[] IGNOREVALS = { "ABSTRACT", "STRUCTURAL",
"AUXILIARY", "MUST", "MAY" };
}

View File

@@ -0,0 +1,74 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import java.util.*;
import java.io.*;
/**
* Specifies how you can retrieve authentication information automatically
* for referrals. If you have set up the search constraints (or the options
* in the <CODE>LDAPConnection</CODE> object) so that automatic referral is
* used, you must define a class that implements this interface.
* <P>
*
* If no class implements this interface, clients that follow automatic
* referrals are authenticated anonymously with subsequent LDAP servers.
* The following example is a simple class that implements this interface.
* Objects of this class check the host and port of the LDAP server that is
* being referred to. If the host and port are "alway.mcom.com:389", the
* directory manager's name and password will be used to authenticate to that
* server. For all other LDAP servers, anonymous authentication is used.
*
* <PRE>
* public class myLDAPRebind implements netscape.ldap.LDAPRebind
* {
* private String myDN;
* private String myPW;
* private LDAPRebindAuth myRebindInfo;
* public myLDAPRebind () {
* myDN = "c=Directory Manager,o=Universal Exports,c=UK";
* myPW = "alway4444";
* }
*
* public LDAPRebindAuth getRebindAuthentication( String host, int port ) {
* if ( host.equalsIgnoreCase( "alway.mcom.com" ) && ( port == 389 ) ) {
* myRebindInfo = new LDAPRebindAuth( myDN, myPW );
* } else {
* myRebindInfo = new LDAPRebindAuth( "", "" );
* }
* return myRebindInfo;
* }
* } </PRE>
*
*
* @version 1.0
*/
public interface LDAPRebind {
/**
* Returns an <CODE>LDAPRebindAuth</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 LDAPRebindAuth object containing authentication information.
* @see netscape.ldap.LDAPRebindAuth
*/
public LDAPRebindAuth getRebindAuthentication(String host,
int port);
}

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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import java.util.*;
import java.io.*;
/**
* 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 LDAPRebindAuth myRebindInfo;
* ...
* public LDAPRebindAuth getRebindAuthentication( String host, int port ) {
* if ( host.equalsIgnoreCase( "alway.mcom.com" ) && ( port == 389 ) ) {
* myRebindInfo = new LDAPRebindAuth( myDN, myPW );
* } else {
* myRebindInfo = new LDAPRebindAuth( "", "" );
* }
* return myRebindInfo;
* } </PRE>
*
* @version 1.0
* @see netscape.ldap.LDAPRebind
*/
public class LDAPRebindAuth {
private String m_dn;
private String m_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 LDAPRebindAuth(String dn, String password) {
m_dn = dn;
m_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 be used for authenticating to
* other LDAP servers during referrals.
*/
public String getDN() {
return m_dn;
}
/**
* Returns the password to be used for reauthentication,
* if the client is set up to follow referrals automatically.
* @return Password to be used for authenticating to other
* LDAP servers during referrals.
*/
public String getPassword() {
return m_password;
}
}

View File

@@ -0,0 +1,147 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import java.util.*;
import netscape.ldap.client.*;
import netscape.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 netscape.ldap.LDAPException
*/
public class LDAPReferralException extends LDAPException {
private String m_referrals[] = null; /* modified for LDAPv3 */
/**
* 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, null);
m_referrals = referrals;
}
/**
* 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 LDAPUrl[] getURLs() {
if (getLDAPErrorMessage() == null) {
return constructsURL(m_referrals);
} else {
return constructsURL(extractReferrals(getLDAPErrorMessage()));
}
}
private LDAPUrl[] constructsURL(String referrals[]) {
if (referrals == null) {
return null;
}
LDAPUrl u[] = new LDAPUrl[referrals.length];
if (u == null) {
return null;
}
for (int i = 0; i < referrals.length; i++) {
try {
u[i] = new LDAPUrl(referrals[i]);
} catch (Exception e) {
return null;
}
}
return u;
}
/**
* Extract referral string from the error message. The
* error string is based on "Referrals Within the
* LDAPv2 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;
}
}

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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.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.props
* ErrorCodes_en.props
* ErrorCodes.props
*
* </pre>
* @see java.util.Locale
*/
class LDAPResourceBundle {
private static final boolean m_debug = false;
private static final String m_suffix = ".props";
private static final String m_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, ie, the 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 = m_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(m_locale_separator);
if (index == -1) {
printDebug("File "+baseName+localeStr+m_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, ie, the name contains
* no locale context and no . suffix
* @param The locale string being inserted within the file name.
* @return The input stream on the property file.
*/
private static InputStream getStream(String baseName, String locale) {
String fStr = baseName+locale+m_suffix;
return (ClassLoader.getSystemResourceAsStream(fStr));
}
/**
* Prints debug messages if the debug mode is on.
* @param str The given message being printed.
*/
private static void printDebug(String str) {
if (m_debug)
System.out.println(str);
}
}

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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
import netscape.ldap.client.opers.JDAPProtocolOp;
import netscape.ldap.client.opers.JDAPResult;
/**
* Represents the response to a particular LDAP operation.
*
* @version 1.0
*/
public class LDAPResponse extends LDAPMessage {
/**
* Constructor
*
* @param msgid message identifier
* @param rsp Operation response
* @param controls Array of controls of 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 which could be matched,
* 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,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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.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 {
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,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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
/**
* Represents the message queue associated with a particular LDAP
* operation or operations.
*
*/
public class LDAPResponseListener extends LDAPMessageQueue{
/**
* Constructor
* @param asynchOp A flag whether the object is used for asynchronous
* LDAP operations
* @see netscape.ldap.LDAPAsynchronousConnection
*/
LDAPResponseListener(boolean asynchOp) {
super(asynchOp);
}
/**
* Blocks until a response is available, or until all operations
* associated with the object have completed or been canceled, and
* returns the response.
*
* @return A response for a LDAP operation or null if there is no
* more outstanding requests
* @exception LDAPException Network error exception
* @exception LDAPInterruptedException The invoking thread was interrupted
*/
public LDAPResponse getResponse() throws LDAPException {
return (LDAPResponse)nextMessage();
}
/**
* Merge two response listeners
* Move/append the content from another response listener 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.getIDs(), 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.getIDs().
* The proper way to handle this scenario is to create a separate listener
* for each new request, and after l.getIDs() has been invoked, merge the
* new request with the existing one.
* @param listener2 The listener to be merged with.
*/
public void merge(LDAPSearchListener listener2) {
super.merge(listener2);
}
/**
* Reports true if a response has been received from the server.
*
* @return A flag whether the response message queue is empty
*/
public boolean isResponseReceived() {
return super.isMessageReceived();
}
/**
* Returns message ids for all outstanding requests
* @return Message id array
*/
public int[] getIDs() {
return super.getIDs();
}
}

View File

@@ -0,0 +1,312 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.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(netscape.ldap.LDAPSocketFactory)
*/
public class LDAPSSLSocketFactory implements LDAPSSLSocketFactoryExt {
/**
* Indicates if client authentication is on.
*/
private boolean m_clientAuth = false;
/**
* Name of class implementing SSLSocket.
*/
private String m_packageName = "netscape.net.SSLSocket";
/**
* The cipher suites
*/
private Object m_cipherSuites = null;
/**
* The Ldap connection
*/
private LDAPConnection m_connection = 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) {
m_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 up.
*/
public LDAPSSLSocketFactory(String className) {
m_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 up.
* @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) {
m_packageName = new String(className);
m_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 up.
* @param cipherSuites The cipher suites to use for SSL connections.
*/
public LDAPSSLSocketFactory(String className, Object cipherSuites) {
m_packageName = new String(className);
m_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.
* @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) {
m_packageName = new String(className);
m_cipherSuites = cipherSuites;
m_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>makeSocket</CODE>.
* @see netscape.ldap.LDAPSSLSocketFactory#isClientAuth
* @see netscape.ldap.LDAPSSLSocketFactory#makeSocket
* 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() {
m_clientAuth = true;
}
/**
* <B>This method is currently not implemented.</B>
* Enables client authentication for an application that uses
* an external (file-based) certificate database.
* Call this method before you call <CODE>makeSocket</CODE>.
* @param certdb The pathname for certificate database
* @param keydb The pathname for private key database
* @param keypwd The password for private key database
* @param certnickname The alias for certificate
* @param keynickname The alias for key
* @see netscape.ldap.LDAPSSLSocketFactory#isClientAuth
* @see netscape.ldap.LDAPSSLSocketFactory#makeSocket
* @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 netscape.ldap.LDAPSSLSocketFactory
*/
public boolean isClientAuth() {
return m_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 m_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 m_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 netscape.ldap.LDAPSSLSocketFactory
*/
public Socket makeSocket(String host, int port)
throws LDAPException {
Socket s = null;
if (m_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.makeSocket: invoking " +
"enablePrivilege: " + e.toString();
throw new LDAPException(msg, LDAPException.PARAM_ERROR);
}
}
try {
String cipherClassName = null;
if (m_cipherSuites != null)
cipherClassName = m_cipherSuites.getClass().getName();
/* Instantiate the SSLSocketFactory implementation, and
find the right constructor */
Class c = Class.forName(m_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 ( (m_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 ( (m_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] = m_cipherSuites;
s = (Socket)(m[i].newInstance(args));
return s;
}
}
throw new LDAPException("No appropriate constructor in " +
m_packageName,
LDAPException.PARAM_ERROR);
} catch (ClassNotFoundException e) {
throw new LDAPException("Class " + m_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,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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.ldap;
/**
* Represents a SSL socket connection that you can use to connect to an
* LDAP server. This interface extends the base interface LDAPSocketFactory
* and it provides the methods for SSL specific matters.
* <P>
*
* @version 1.0
* @see LDAPSocketFactory
* @see LDAPConnection#LDAPConnection(netscape.ldap.LDAPSocketFactory)
*/
public interface LDAPSSLSocketFactoryExt extends LDAPSocketFactory {
/**
* Returns <code>true</code> if client authentication is enabled.
* @see netscape.ldap.LDAPSSLSocketFactory#enableClientAuth
*/
public boolean isClientAuth();
/**
* 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();
}

View File

@@ -0,0 +1,348 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
package netscape.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(netscape.ldap.LDAPSocketFactory)
*/
public class LDAPSSLSocketWrapFactory implements LDAPSSLSocketFactoryExt {
/**
* The constructor with the specified package for security
* @param className The name of a class which has an implementation
* of SSL Socket extending Object class.
*/
public LDAPSSLSocketWrapFactory(String className) {
m_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 SSL Socket extending Object class.
* @param cipherSuites The cipher suites.
*/
public LDAPSSLSocketWrapFactory(String className, Object cipherSuites) {
m_packageName = new String(className);
m_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 makeSocket(String host, int port) throws LDAPException {
LDAPSSLSocket s = null;
try {
if (m_cipherSuites == null)
s = new LDAPSSLSocket(host, port, m_packageName);
else
s = new LDAPSSLSocket(host, port, m_packageName,
m_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 true if client authentication is enabled, otherwise, false if
* client authentication is disabled.
*/
public boolean isClientAuth() {
return m_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 makeSocket() 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 m_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 m_cipherSuites;
}
/**
* Indicates if client authentication is on.
*/
private boolean m_clientAuth = false;
/**
* Name of class implementing SSLSocket.
*/
private String m_packageName = null;
/**
* The cipher suites
*/
private Object m_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();
m_packageName = packageName;
try {
// instantiate the SSLSocketFactory implementation, and
// find the right constructor
Class c = Class.forName(m_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);
m_socket = (Object)(m[i].newInstance(args));
return;
}
}
throw new LDAPException("No appropriate constructor in " +
m_packageName, LDAPException.PARAM_ERROR);
} catch (ClassNotFoundException e) {
throw new LDAPException("Class " + m_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();
m_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(m_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;
m_socket = (Object)(m[i].newInstance(args));
return;
}
}
throw new LDAPException("No appropriate constructor in " +
m_packageName, LDAPException.PARAM_ERROR);
} catch (ClassNotFoundException e) {
throw new LDAPException("Class " + m_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(m_socket, "getInputStream", null);
return (InputStream)obj;
} catch (LDAPException e) {
printDebug(e.toString());
}
return null;
}
public OutputStream getOutputStream() {
try {
Object obj = invokeMethod(m_socket, "getOutputStream", null);
return (OutputStream)obj;
} catch (LDAPException e) {
printDebug(e.toString());
}
return null;
}
public void close() throws IOException {
try {
invokeMethod(m_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(m_socket, "close", args);
} catch (LDAPException e) {
printDebug(e.toString());
}
}
public InetAddress getInetAddress() {
try {
Object obj = invokeMethod(m_socket, "getInetAddress", null);
return (InetAddress)obj;
} catch (LDAPException e) {
printDebug(e.toString());
}
return null;
}
public int getLocalPort() {
try {
Object obj = invokeMethod(m_socket, "getLocalPort", null);
return ((Integer)obj).intValue();
} catch (LDAPException e) {
printDebug(e.toString());
}
return -1;
}
public int getPort() {
try {
Object obj = invokeMethod(m_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)(m_methodLookup.get(name)))
!= null)
return method;
Class c = Class.forName(m_packageName);
java.lang.reflect.Method[] m = c.getMethods();
for (int i = 0; i < m.length; i++ ) {
if (m[i].getName().equals(name)) {
m_methodLookup.put(name, m[i]);
return m[i];
}
}
throw new LDAPException("Method " + name + " not found in " +
m_packageName);
} catch (ClassNotFoundException e) {
throw new LDAPException("Class "+ m_packageName + " not found");
}
}
private void printDebug(String msg) {
if (m_debug) {
System.out.println(msg);
}
}
private final boolean m_debug = true;
private Object m_socket;
private Hashtable m_methodLookup = new Hashtable();
private String m_packageName = null;
}

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