1
/** BEGIN COPYRIGHT BLOCK
2
* Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
3
* Copyright (C) 2005 Red Hat, Inc.
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation version 2 of the License.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
* END COPYRIGHT BLOCK **/
20
package com.netscape.admin.dirserv;
25
import java.awt.event.ActionEvent;
26
import java.awt.event.ActionListener;
28
import com.netscape.management.client.*;
29
import com.netscape.management.client.console.ConsoleInfo;
30
import com.netscape.management.client.util.ResourceSet;
31
import com.netscape.management.client.util.Debug;
32
import com.netscape.management.client.util.RemoteImage;
33
import com.netscape.management.client.util.LDAPUtil;
34
import com.netscape.management.client.util.UtilConsoleGlobals;
35
import netscape.ldap.*;
36
import netscape.ldap.util.*;
37
import com.netscape.admin.dirserv.task.CGITask;
38
import com.netscape.admin.dirserv.task.Remove;
39
import com.netscape.admin.dirserv.task.Start;
42
* Handles cloning of directory servers over LDAP. There will be a source
43
* LDAP server and a destination LDAP server. There will also be a
44
* connection to the Configuration server because we will need to read
45
* some entries from that server.
52
public class CloneServer {
55
* The configDS is the connection to the Configuration directory where
56
* the topology and SIE information is stored. The sourceDN is the SIE
57
* of the source DS, and the destDN is the SIE of the destination DS.
59
public static boolean cloneServer(LDAPConnection configDS, String sourceDN,
60
String destDN, JFrame frame) {
61
Debug.println("CloneServer.cloneServer: begin: configDS=" +
62
DSUtil.format(configDS) + " sourceDN=" + sourceDN +
64
// sourceValues will contain the attribute/value pairs from the DN
65
Hashtable sourceValues = new Hashtable();
66
LDAPConnection source = getConnection(configDS, sourceDN, sourceValues,
71
// destValues will contain the attribute/value pairs from the DN
72
Hashtable destValues = new Hashtable();
73
LDAPConnection dest = getConnection(configDS, destDN, destValues,
78
} catch (Exception e) {
83
// now we have ldap connections to the source and destination for the
84
// clone; we want to read the configuration entries in the source and
85
// write the values to the corresponding entries on the destination
86
DN[] entryList = getEntriesToClone(source, frame);
87
if (entryList == null) {
88
DSUtil.showErrorDialog(frame, "clonesourceempty", "cn=config");
91
} catch (Exception e) {
95
} catch (Exception e) {
100
for (int ii = 0; ii < entryList.length; ++ii) {
101
Debug.println("entryList[" + ii + "]=" + entryList[ii]);
104
String oldDir = replace(sourceValues.get("serverroot").toString() +
106
sourceValues.get("nsserverid").toString(),
109
String newDir = replace(destValues.get("serverroot").toString() +
111
destValues.get("nsserverid").toString(),
114
// some attributes can only be cloned if the servers are not
115
// running on the same host, so we need to determine if the
116
// source and destination hosts are the same
117
String sourceHost = (String)sourceValues.get("serverhostname");
119
sourceHost = DSUtil.canonicalHost(sourceHost);
120
} catch (UnknownHostException e) {
122
if (sourceHost == null || sourceHost.equals(""))
123
sourceHost = (String)sourceValues.get("serverhostname");
125
String destHost = (String)destValues.get("serverhostname");
127
destHost = DSUtil.canonicalHost(destHost);
128
} catch (UnknownHostException e) {
130
if (destHost == null || destHost.equals(""))
131
destHost = (String)destValues.get("serverhostname");
133
boolean hostsAreSame = sourceHost.equalsIgnoreCase(destHost);
135
// for each entry, read it from the source, delete those attributes
136
// we don't want to copy, and write the entry to the destination
137
String err = null; // which error dialog
138
String[] args = null; // arguments for dialog
139
boolean cloneWasSuccessful = true;
141
cloneWasSuccessful && index < entryList.length; ++index) {
142
LDAPEntry entry = null;
143
Debug.println("CloneServer.cloneServer: reading entry DN=" +
144
entryList[index].toString());
145
boolean done = false;
148
entry = source.read(entryList[index].toString());
149
// if the entry is null or contains no elements, this
150
// usually means that we didn't have permission to read
151
// that particular entry, so we need to reauthenticate
152
// as a more priviledged user
154
throw new LDAPException("no elements",
155
LDAPException.INSUFFICIENT_ACCESS_RIGHTS);
158
} catch (LDAPException lde) {
159
done = reauthenticate(source, lde,
160
entryList[index].toString(),
161
frame, "clonesourceread");
162
if (done) // unhandled error or cancel
163
cloneWasSuccessful = false;
168
Debug.println("CloneServer.cloneServer: modifying DN=" +
170
LDAPModificationSet ldapmodset = getMods(entry, dest, frame,
171
hostsAreSame, oldDir,
175
if (ldapmodset == null || ldapmodset.size() == 0) {
176
done = true; // nothing to be done
178
Debug.println("CloneServer.cloneServer: DN=" +
179
entry.getDN() + " num attrs to modify=" +
184
dest.modify(entryList[index].toString(), ldapmodset);
186
} catch (LDAPException lde) {
187
done = reauthenticate(dest, lde,
188
entryList[index].toString(),
189
frame, "clonedestwrite");
190
if (done) // unhandled error or cancel
191
cloneWasSuccessful = false;
194
} else { // entry is null
195
Debug.println("DSAdmin.cloneFrom(): could not read entry " +
196
"from source " + DSUtil.format(source));
197
err = "clonesourceempty";
198
args = new String[1];
199
args[0] = entryList[index].toString();
203
DSUtil.showErrorDialog(frame, err, args);
204
cloneWasSuccessful = false;
206
err = null; // reset for next entry
207
args = null; // reset for next entry
210
if (cloneWasSuccessful)
211
cloneWasSuccessful = cloneSchema(source, dest, frame);
215
} catch (Exception e) {
219
} catch (Exception e) {
222
if (cloneWasSuccessful) {
223
DSUtil.showInformationDialog(frame, "clonesuccess",
226
DSUtil.showErrorDialog(frame, "clonefailed", (String)null);
229
return cloneWasSuccessful;
232
private static LDAPConnection getConnection(LDAPConnection configDS,
233
String sieDN, Hashtable values,
235
values.put("nsbinddn", "");
236
values.put("cn", "");
237
values.put("serverroot", "");
238
values.put("nsserverid", "");
240
LDAPConnection ldc = null;
242
ldc = DSAdmin.getLDAPConnection(configDS, sieDN,
246
} catch (LDAPException lde) {
247
String host = (String)values.get("serverhostname");
248
String port = (String)values.get("nsserverport");
249
Debug.println("CloneServer.cloneServer(): could not read DN = " +
250
sieDN + " or connect to " + host + ":" + port +
251
" LDAP exception = " + lde);
252
} catch (Exception other) {
253
String host = (String)values.get("serverhostname");
254
String port = (String)values.get("nsserverport");
255
Debug.println("CloneServer.cloneServer(): could not read DN = " +
256
sieDN + " or connect to " + host + ":" + port +
257
" exception = " + other);
260
if (ldc == null || !ldc.isConnected()) {
261
String name = (String)values.get("cn");
262
String host = (String)values.get("serverhostname");
263
String port = (String)values.get("nsserverport");
264
DSUtil.showErrorDialog(frame, "120", name + " " +
273
* The entries to clone from the source can be found by enumerating the
274
* nsslapd-privatenamespaces attributes in the entry cn=config and by
275
* getting these entries and their corresponding ldbm-config children.
276
* Also, by looking at cn=features, cn=config and its children.
278
static private DN[] getEntriesToClone(LDAPConnection ldc, JFrame frame) {
279
Vector entryList = null;
280
String configDN = "cn=config";
281
// list of DNs to ignore
282
String[] ignoreList = { "cn=monitor", "cn=schema", "cn=encryption",
284
String feConfigAttr = "nsslapd-privatenamespaces";
285
LDAPEntry configEntry = null;
286
String[] attrs = { feConfigAttr };
287
boolean done = false;
291
configEntry = ldc.read(configDN, attrs);
292
// if the entry is null or contains no elements, this
293
// usually means that we didn't have permission to read
294
// that particular entry, so we need to reauthenticate
295
// as a more priviledged user
296
if (configEntry == null) {
297
throw new LDAPException("no elements",
298
LDAPException.INSUFFICIENT_ACCESS_RIGHTS);
301
} catch (LDAPException lde) {
302
done = reauthenticate(ldc, lde, configDN, frame,
307
if (configEntry == null)
310
entryList = new Vector();
311
for (int ii = 0; ii < attrs.length; ++ii) {
312
Enumeration en = configEntry.getAttribute(attrs[ii]).
314
while (en.hasMoreElements()) {
315
String dn = (String)en.nextElement();
318
continue; // ignore root DSE
320
for (int jj = 0; jj < ignoreList.length; ++jj) {
321
if (dn.indexOf(ignoreList[jj]) != -1) {
330
// for the config entries, we need to do a subtree
331
// search to get all of their entries as well
332
LDAPSearchResults result = null;
333
String filter = "(objectclass=*)";
336
result = ldc.search(dn, LDAPConnection.SCOPE_SUB,
337
filter, null, false);
338
} catch (LDAPException e) {
339
Debug.println("error CloneServer.getEntriesToClone: LDAP" +
340
" search failed: " + filter);
341
Debug.println("error CloneServer.getEntriesToClone: " +
342
"could not find any servers under " +
343
dn + " error: " + e);
346
while (result != null && result.hasMoreElements()) {
347
LDAPEntry lde = (LDAPEntry)result.nextElement();
348
for (int jj = 0; jj < ignoreList.length; ++jj) {
349
if (lde.getDN().indexOf(ignoreList[jj]) != -1) {
355
entryList.addElement(new DN(lde.getDN()));
361
if (entryList != null && entryList.size() > 0) {
362
retval = new DN[entryList.size()];
363
entryList.copyInto(retval);
369
static private boolean reauthenticate(
370
LDAPConnection ldc, LDAPException lde, String dn, JFrame frame,
373
boolean done = false;
374
Debug.println("CloneServer.reauthenticate(): LDAP error code=" +
375
lde.getLDAPResultCode() + " error=" +
377
Debug.println("CloneServer.reauthenticate(): could not read DN = " +
378
dn + " from source ldap = " +
380
// if the read failed due to permissions, notify the user
381
// via a dialog and ask the user to authenticate using a
382
// different user id/password. If the user selects OK,
383
// popup the password dialog asking for another user id and
384
// password. If the user hits OK, update the userid and
385
// password in the _ldc object and retry the modify. Keep
386
// looping until: 1. The modify succeeds 2. The user hits
387
// Cancel in either the confirm dialog or the password
388
// dialog 3. we get some other type of LDAP error
389
if (lde.getLDAPResultCode() ==
390
LDAPException.INSUFFICIENT_ACCESS_RIGHTS) {
392
DSUtil.showPermissionDialog(frame, ldc);
393
// hack; for some reason, reauthenticate does not
394
// rebind to the server; so, I disconnect in order to
395
// force a re-connection
398
} catch (Exception e) {
400
done = !DSUtil.reauthenticate(ldc, frame, null,
401
ldc.getAuthenticationDN(),
404
Debug.println("CloneServer.reauthenticate(): could not " +
406
"the exception, entry will not be " +
407
"read from source " + DSUtil.format(ldc));
409
String[] args = { dn, lde.toString() };
410
DSUtil.showErrorDialog(frame, err, args);
413
done = true; // could not read entry ...
419
static private boolean cloneSchema(LDAPConnection source,
422
String schemaDN = "cn=schema";
424
LDAPEntry sourceSchema = null;
426
sourceSchema = source.read(schemaDN);
427
} catch (LDAPException e) {
429
String[] args = { schemaDN, e.toString() };
430
DSUtil.showErrorDialog(frame, "clonesourceread", args);
433
if (sourceSchema == null)
436
Debug.println("CloneServer.cloneSchema(): read source schema");
437
LDAPEntry destSchema = null;
439
destSchema = dest.read(schemaDN);
440
} catch (LDAPException e) {
442
String[] args = { schemaDN, e.toString() };
443
DSUtil.showErrorDialog(frame, "clonedestwrite", args);
446
if (destSchema == null)
449
Debug.println("CloneServer.cloneSchema(): read dest schema");
450
// read the dest schema values into a hashtable
451
Hashtable dhash = new Hashtable();
452
LDAPAttributeSet las = destSchema.getAttributeSet();
453
for (Enumeration attrs = las.getAttributes();
454
attrs.hasMoreElements();) {
455
LDAPAttribute la = (LDAPAttribute)attrs.nextElement();
456
for (Enumeration vals = la.getStringValues();
457
vals.hasMoreElements();) {
458
String val = (String)vals.nextElement();
461
dhash.put(val, la.getName());
465
Debug.println("CloneServer.cloneSchema(): dest schema size=" +
467
// loop through the source looking for values which are not
468
// present in the dest
469
Vector ocList = null; // for objectclass mods
470
LDAPModificationSet lms = null; // for attribute mods
471
int op = LDAPModification.ADD;
472
las = sourceSchema.getAttributeSet();
473
for (Enumeration attrs = las.getAttributes();
474
attrs.hasMoreElements();) {
475
LDAPAttribute la = (LDAPAttribute)attrs.nextElement();
476
LDAPAttribute newla = null;
477
for (Enumeration vals = la.getStringValues();
478
vals.hasMoreElements();) {
479
String val = (String)vals.nextElement();
482
if (!dhash.containsKey(val)) {
484
Objectclasses should be added via the
485
LDAPSchemaElement.add interface rather than by
486
the modify() interface
488
if (isObjectClass(la)) {
490
ocList = new Vector();
491
ocList.addElement(new LDAPObjectClassSchema(val));
494
newla = new LDAPAttribute(la.getName());
497
Debug.println(9, "CloneServer.cloneSchema(): found " +
498
"attribute value not present on dest=" +
502
// now newla contains only those values not present on the dest
505
lms = new LDAPModificationSet();
510
if ((lms == null || lms.size() == 0) &&
511
((ocList == null) || (ocList.size() == 0))) {
512
Debug.println("CloneServer.cloneSchema(): source and dest are" +
513
" identical, nothing to modify");
517
Debug.println("CloneServer.cloneSchema(): modifying " +
518
lms.size() + " schema elements");
520
dest.modify(schemaDN, lms);
521
for (int ii = 0; ocList != null && ii < ocList.size(); ++ii) {
522
LDAPObjectClassSchema locs =
523
(LDAPObjectClassSchema)ocList.elementAt(ii);
526
} catch (LDAPException e) {
528
String[] args = { schemaDN, e.toString() };
529
DSUtil.showErrorDialog(frame, "clonedestwrite", args);
533
Debug.println("CloneServer.cloneSchema(): success");
537
static private LDAPAttribute convertValue(LDAPAttribute la, int factor) {
538
Vector newVals = new Vector();
539
for (Enumeration e = la.getStringValues(); e.hasMoreElements();) {
540
String sval = (String)e.nextElement();
543
Debug.println("Converting value=" + sval + " using" +
544
" factor=" + factor);
545
ival = Integer.parseInt(sval);
548
sval = Integer.toString(ival);
549
Debug.println("Converting new value=" + sval);
551
} catch (Exception ex) {
553
newVals.addElement(sval);
557
String[] nv = new String[newVals.size()];
558
newVals.copyInto(nv);
559
return new LDAPAttribute(la.getName(), nv);
562
static private String replace(String src, String old, String news) {
563
int index = src.indexOf(old);
567
StringBuffer sb = new StringBuffer();
569
while (index != -1) {
570
// copy the src into the buffer
571
sb.append(src.substring(start, index));
572
// copy the new string instead of the old one
574
// start the next copy after this one
575
start = index + old.length();
576
// find the next occurance of the old string
577
index = src.indexOf(old, start);
579
// copy remainder of string
580
if (start < src.length())
581
sb.append(src.substring(start));
583
return sb.toString();
586
static private LDAPAttribute replaceValue(LDAPAttribute la, String oldStr,
588
Vector newVals = new Vector();
589
for (Enumeration e = la.getStringValues(); e.hasMoreElements();) {
590
String sval = (String)e.nextElement();
591
newVals.addElement(replace(sval, oldStr, newStr));
594
String[] nv = new String[newVals.size()];
595
newVals.copyInto(nv);
596
return new LDAPAttribute(la.getName(), nv);
599
static private LDAPModificationSet getMods(LDAPEntry sourceEntry,
602
boolean hostsAreSame,
603
String oldDir, String newDir) {
605
LDAPEntry destEntry = null;
606
boolean done = false;
607
Debug.println("CloneServer.getMods(): getting attributes to modify" +
608
" for DN=" + sourceEntry.getDN());
609
boolean noEntry = false;
612
destEntry = dest.read(sourceEntry.getDN());
613
// if the entry is null or contains no elements, this
614
// usually means that we didn't have permission to read
615
// that particular entry, so we need to reauthenticate
616
// as a more privileged user
617
if (destEntry == null) {
618
throw new LDAPException("no elements",
619
LDAPException.INSUFFICIENT_ACCESS_RIGHTS);
622
} catch (LDAPException lde) {
623
if (lde.getLDAPResultCode() == LDAPException.NO_SUCH_OBJECT) {
626
// its ok if the dest entry does not exist because we will
629
done = reauthenticate(dest, lde,
631
frame, "clonedestread");
636
if (destEntry == null && !noEntry)
639
Debug.println("CloneServer.getMods(): got dest entry DN=" +
640
sourceEntry.getDN());
641
LDAPAttributeSet ldas = sourceEntry.getAttributeSet();
643
LDAPModificationSet ldapmodset = new LDAPModificationSet();
644
// loop through sourceEntry attributes; if the attribute exists on the
645
// source entry but not on the dest entry, the op is add otherwise
647
for (Enumeration e = ldas.getAttributes();
648
e.hasMoreElements();) {
649
LDAPAttribute lda = (LDAPAttribute)e.nextElement();
650
Enumeration e2 = lda.getStringValues();
651
// Make sure the attribute has a value. Only attributes
652
// which have a value will be ADDed or REPLACEd. Attributes
653
// which do not have a value will be handled by the delete
658
int op = LDAPModification.REPLACE;
659
if ((destEntry == null) ||
660
!hasAValue(destEntry.getAttribute(lda.getName())))
661
op = LDAPModification.ADD;
662
else if (noCopyAttrs.containsKey(lda.getName()))
663
continue; // we cannot replace noCopyAttrs, but we
666
// see if we need to do some conversion of the value before
667
// we write it to the dest
668
if (convertAttrs.containsKey(lda.getName())) {
669
Debug.println("converting attribute " +
672
(Integer)convertAttrs.get(lda.getName());
673
lda = convertValue(lda, factor.intValue());
674
} else if (replacePathAttrs.containsKey(lda.getName())) {
675
lda = replaceValue(lda, oldDir, newDir);
676
} else if (hostsAreSame &&
677
differentHostsAttrs.containsKey(lda.getName())) {
678
continue; // do not add this attribute to the
682
ldapmodset.add(op, lda);
685
// loop through destEntry attributes; if the attribute exists on
686
// the dest entry but not the source, or if the attribute value
687
// is a special delete or remove value, it should be deleted from
689
if (destEntry != null) {
690
ldas = destEntry.getAttributeSet();
691
for (Enumeration e = ldas.getAttributes();
692
e.hasMoreElements();) {
693
LDAPAttribute lda = (LDAPAttribute)e.nextElement();
695
continue; // attribute does not exist on dest
697
if (hasAValue(sourceEntry.getAttribute(lda.getName())))
698
continue; // attribute exists on source
700
int op = LDAPModification.DELETE;
701
// check for attributes which are not removed the conventional
703
if (specialRemoveAttrs.containsKey(lda.getName())) {
704
lda.addValue(specialRemoveAttrs.get(lda.getName()).toString());
705
op = LDAPModification.REPLACE;
708
ldapmodset.add(op, lda);
716
* An attribute has a value if its non null, if its size != 0, if
717
* it has a list of values, and if the values do not contain the
718
* special null or delete value
720
static private boolean hasAValue(LDAPAttribute lda) {
722
Debug.println("CloneServer.hasAValue(): attr is null");
726
if (lda.size() == 0) {
727
Debug.println("CloneServer.hasAValue(): attr=" + lda.getName() +
732
Enumeration e = lda.getStringValues();
733
if ((e == null) || !e.hasMoreElements()) {
734
Debug.println("CloneServer.hasAValue(): attr=" + lda.getName() +
739
boolean hasAVal = false;
740
if (specialDeleteAttrs.containsKey(lda.getName())) {
741
Debug.println("checking for deletion of attr=" + lda.getName() +
742
" value=" + lda.toString());
743
for (; !hasAVal && e.hasMoreElements(); ) {
744
String val = (String)e.nextElement();
746
(String)specialDeleteAttrs.get(lda.getName());
747
hasAVal = (val != null) && !val.equals(delval);
755
Debug.println("CloneServer.hasAValue(): attr=" + lda.getName() +
756
" has all null values");
758
Debug.println(9, "CloneServer.hasAValue(): attr=" + lda.getName() +
759
" has value=" + lda.toString());
765
* Returns true if the attribute is the raw objectclass representation
766
* from the attribute value in the schema entry
768
static private boolean isObjectClass(LDAPAttribute la) {
769
return la.getName().equalsIgnoreCase("objectclasses");
773
* noCopyAttrs is a look up table of attributes which should not be
774
* copied from the source to the dest. Most of these are pretty
777
static private Hashtable noCopyAttrs = new Hashtable();
779
noCopyAttrs.put("cn", "");
780
noCopyAttrs.put("objectclass", "");
781
noCopyAttrs.put("oid", "");
782
noCopyAttrs.put("nsslapd-config", "");
783
noCopyAttrs.put("nsslapd-betype", "");
784
noCopyAttrs.put("nsslapd-privatenamespaces", "");
785
noCopyAttrs.put("nsslapd-rootdn", "");
786
noCopyAttrs.put("nsslapd-rootpw", "");
787
noCopyAttrs.put("nsslapd-instancedir", "");
788
noCopyAttrs.put("nsslapd-useroc", "");
789
noCopyAttrs.put("nsslapd-userat", "");
790
noCopyAttrs.put("nsslapd-localhost", "");
791
noCopyAttrs.put("nsslapd-security", "");
792
noCopyAttrs.put("nsslapd-plugin", "");
793
noCopyAttrs.put("nsslapd-include", "");
794
noCopyAttrs.put("nsslapd-backendconfig", "");
795
noCopyAttrs.put("nsslapd-accesslog", "");
796
noCopyAttrs.put("nsslapd-accesslog-list", "");
797
noCopyAttrs.put("nsslapd-errorlog", "");
798
noCopyAttrs.put("nsslapd-errorlog-list", "");
799
noCopyAttrs.put("nsslapd-auditlog", "");
800
noCopyAttrs.put("nsslapd-auditlog-list", "");
801
noCopyAttrs.put("nsslapd-requiresrestart", "");
802
noCopyAttrs.put("nsslapd-database", "");
803
noCopyAttrs.put("nsslapd-directory", "");
804
noCopyAttrs.put("nsslapd-idlistscanlimit", ""); // why?
805
noCopyAttrs.put("nsslapd-parentcheck", ""); // why?
806
noCopyAttrs.put("nsslapd-mode", ""); // why?
807
noCopyAttrs.put("nsslapd-groupevalnestlevel", ""); // why?
808
// only the nsslapd-pluginenabled attribute should be copied
809
noCopyAttrs.put("nsslapd-pluginpath", "");
810
noCopyAttrs.put("nsslapd-plugininitfunc", "");
811
noCopyAttrs.put("nsslapd-plugintype", "");
812
noCopyAttrs.put("nsslapd-pluginid", "");
813
noCopyAttrs.put("nsslapd-pluginversion", "");
814
noCopyAttrs.put("nsslapd-pluginvendor", "");
815
noCopyAttrs.put("nsslapd-plugindescription", "");
816
noCopyAttrs.put("nsslapd-backend", "");
817
noCopyAttrs.put("nsslapd-referralmode", "");
821
* This is a table of attributes which have a special value
822
* which indicates that the destination should be deleted
823
* usually, if the source attribute is empty or has a null value,
824
* it means the destination attribute should be deleted. There
825
* are also special attributes which can have a special value
826
* which means the destination should be deleted
827
* the key is the attribute name and the value is the special
828
* value which means deletion
830
static private Hashtable specialDeleteAttrs = new Hashtable();
832
specialDeleteAttrs.put("nsslapd-changelogmaxentries", "0");
833
specialDeleteAttrs.put("nsslapd-changelogmaxage", "0");
834
specialDeleteAttrs.put("nsslapd-accesslog-logmaxdiskspace", "0");
835
specialDeleteAttrs.put("nsslapd-errorlog-logmaxdiskspace", "0");
836
specialDeleteAttrs.put("nsslapd-auditlog-logmaxdiskspace", "0");
837
specialDeleteAttrs.put("nsslapd-accesslog-maxlogsize", "0");
838
specialDeleteAttrs.put("nsslapd-errorlog-maxlogsize", "0");
839
specialDeleteAttrs.put("nsslapd-auditlog-maxlogsize", "0");
843
* this is a table of attributes whose values must be converted
844
* by dividing by an integral before writing to the destination
846
static private Hashtable convertAttrs = new Hashtable();
848
// convertAttrs.put("passwordmaxage", new Integer(86400));
849
// convertAttrs.put("passwordwarning", new Integer(86400));
853
* this is a table of attributes whose values must undergo
854
* a string replacement of the path
856
static private Hashtable replacePathAttrs = new Hashtable();
858
replacePathAttrs.put("nsslapd-changelogdir", "");
862
* this is a table of attributes that we only want to clone
863
* if the source and the destination are on different hosts
865
static private Hashtable differentHostsAttrs = new Hashtable();
867
differentHostsAttrs.put("nsslapd-port", "");
868
differentHostsAttrs.put("nsslapd-secureport", "");
869
differentHostsAttrs.put("nsslapd-ntsynch-port", "");
873
* this is a table of attributes which have a special remove
874
* value e.g. we don't do an LDAP REMOVE, we just set the
875
* value of the attribute to this special value
877
static private Hashtable specialRemoveAttrs = new Hashtable();
879
specialRemoveAttrs.put("nsslapd-referral", "remove");