From 996f91f191f6fb87b5d1ea52c3f1b943f0764a9c Mon Sep 17 00:00:00 2001
From: ugaston <ugaston@localhost>
Date: Fri, 22 Jan 2010 17:52:57 +0000
Subject: [PATCH] Add EclReadAndPlay util
---
opends/tests/staf-tests/shared/java/ldapjdk/Writer.java | 122 +++
opends/tests/staf-tests/shared/java/ldapjdk/ImprovedLDAPConnection.java | 200 +++++
opends/tests/staf-tests/shared/java/ldapjdk/CSN.java | 62 +
opends/tests/staf-tests/shared/java/ldapjdk/Server.java | 48 +
opends/tests/staf-tests/shared/java/ldapjdk/LDIF.java | 798 +++++++++++++++++++++++
opends/tests/staf-tests/shared/java/ldapjdk/Reader.java | 277 ++++++++
opends/tests/staf-tests/shared/java/ldapjdk/Change.java | 163 ++++
opends/tests/staf-tests/shared/java/ldapjdk/EclReadAndPlay.java | 334 +++++++++
8 files changed, 2,004 insertions(+), 0 deletions(-)
diff --git a/opends/tests/staf-tests/shared/java/ldapjdk/CSN.java b/opends/tests/staf-tests/shared/java/ldapjdk/CSN.java
new file mode 100644
index 0000000..97b412d
--- /dev/null
+++ b/opends/tests/staf-tests/shared/java/ldapjdk/CSN.java
@@ -0,0 +1,62 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2010 Sun Microsystems, Inc.
+ */
+
+
+class CSN implements Comparable<CSN> {
+
+ String value;
+
+ public CSN (String value) {
+ this.value = value;
+ }
+
+ public int compareTo (CSN anotherCSN) {
+
+ if (this.value.equals(anotherCSN.value)) // same CSN value
+ return 0;
+
+ Long i = Long.valueOf(this.value.substring(0,12),16 );
+ Long l = Long.valueOf(anotherCSN.value.substring(0,12),16 );
+
+ return(i.compareTo(l));
+ }
+
+ public boolean equals(Object anotherCSN) {
+ if (this.value.equals(anotherCSN))
+ return true;
+ else
+ return false;
+ }
+
+ public String getValue (){
+ return(value);
+ }
+
+ public String toString (){
+ return(value);
+ }
+}
diff --git a/opends/tests/staf-tests/shared/java/ldapjdk/Change.java b/opends/tests/staf-tests/shared/java/ldapjdk/Change.java
new file mode 100644
index 0000000..dee13aa
--- /dev/null
+++ b/opends/tests/staf-tests/shared/java/ldapjdk/Change.java
@@ -0,0 +1,163 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2010 Sun Microsystems, Inc.
+ */
+
+import netscape.ldap.*;
+import netscape.ldap.util.*;
+import java.util.ArrayList;
+
+class Change {
+ int changeNumber = 0;
+ String changelogCookie = null;
+ CSN csn;
+ String type = "";
+ String dn = "";
+ ArrayList<String> changes = new ArrayList<String>(2);
+ String change = "";
+ String replicaIdentifier = null;
+ String changeNumberValue = null;
+ String nsUniqueId = "";
+ boolean deleteOldRDN = false;
+ String newRDN = null;
+ String newSuperior = null;
+
+
+ public Change(LDAPEntry entry) throws Exception {
+
+
+ LDAPAttribute attr = entry.getAttribute("replicaIdentifier");
+ if ( attr == null ) {
+ throw new Exception("No value found for replicaIdentifier");
+ }
+ replicaIdentifier = attr.getStringValueArray()[0];
+
+
+ attr = entry.getAttribute("changeNumber");
+ if ( attr == null ) {
+ throw new Exception("No value found for changeNumber");
+ }
+ changeNumberValue = attr.getStringValueArray()[0];
+ changeNumber = Integer.parseInt(changeNumberValue);
+
+ attr = entry.getAttribute("changelogCookie");
+ if ( attr != null ) {
+ changelogCookie = attr.getStringValueArray()[0];
+ }
+
+
+ attr = entry.getAttribute("replicationCSN");
+ if ( attr == null ) {
+ throw new Exception("No value found for replicationCSN");
+ }
+ csn = new CSN(attr.getStringValueArray()[0]);
+
+ attr = entry.getAttribute("targetDN");
+ if ( attr == null ) {
+ throw new Exception("No value found for targetDN");
+ }
+ dn = attr.getStringValueArray()[0];
+
+ attr = entry.getAttribute("changeType");
+ if ( attr == null ) {
+ throw new Exception("No value found for changeType");
+ }
+ type = attr.getStringValueArray()[0];
+
+
+// attr = entry.getAttribute("targetUniqueId");
+// if ( attr == null ) {
+// throw new Exception("No value found for targetUniqueId");
+// }
+// nsUniqueId=attr.getStringValueArray()[0];
+ attr = entry.getAttribute("targetEntryUUID");
+ if ( attr == null ) {
+ throw new Exception("No value found for targetEntryUUID");
+ }
+ nsUniqueId = attr.getStringValueArray()[0];
+
+
+ // modrdn
+ if ( type.equals("modrdn") ) {
+ attr = entry.getAttribute("deleteOldRDN");
+ if ( attr == null ) {
+ throw new Exception("No value found for deleteOldRDN");
+ }
+ deleteOldRDN = Boolean.getBoolean(attr.getStringValueArray()[0]);
+
+ attr = entry.getAttribute("newRDN");
+ if ( attr == null ) {
+ throw new Exception("No value found for newRDN");
+ }
+ newRDN = attr.getStringValueArray()[0];
+
+ attr = entry.getAttribute("newSuperior");
+ if ( attr != null ) {
+ newSuperior=attr.getStringValueArray()[0];
+ }
+ }
+
+ // Conflict
+ attr = entry.getAttribute("changeHasReplFixupOp");
+ if ( attr != null ) {
+ change = attr.getStringValueArray()[0];
+ if ( change.trim().endsWith("-") ) {
+ change = change.substring(0, change.length()-3) + "\r\n";
+ }
+ String changeHasReplFixupOp=change.replaceFirst("targetDn", "dn") + "\r\n";
+
+ // println ("INFO", "FixupOp (csn="+ csn+"):\n" + changeHasReplFixupOp);
+ changes.add(changeHasReplFixupOp);
+ }
+
+ attr = entry.getAttribute("changes");
+ if ( attr != null ) {
+ change = attr.getStringValueArray()[0];
+ if ( change.trim().endsWith("-") ) {
+ change = change.substring(0, change.length()-3) + "\r\n";
+ }
+ }
+
+
+ if ( type.equals("modify") && ( change.equals("") ) ) {
+ throw new Exception("Attribute changes is empty - replicationCSN="+ csn);
+ //EclReadAndPlay.accessOut.println (getDate() + "- WARNING: Ignore change csn=" + csn );
+ }
+
+ String myChange = "dn: " + dn + "\n" +
+ "changetype: " + type + "\n" +
+ change +"\n";
+
+ changes.add(myChange);
+
+ changes.trimToSize();
+
+ }
+
+
+ public String toString() {
+ return ("change number " + changeNumber + " (csn="+csn +")");
+ }
+}
diff --git a/opends/tests/staf-tests/shared/java/ldapjdk/EclReadAndPlay.java b/opends/tests/staf-tests/shared/java/ldapjdk/EclReadAndPlay.java
new file mode 100644
index 0000000..b1b2ce0
--- /dev/null
+++ b/opends/tests/staf-tests/shared/java/ldapjdk/EclReadAndPlay.java
@@ -0,0 +1,334 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2010 Sun Microsystems, Inc.
+ */
+
+import netscape.ldap.*;
+import netscape.ldap.util.*;
+
+import java.util.*;
+import java.io.*;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+
+class EclReadAndPlay {
+
+ // dbPath --> stores files containing csn of identifiers
+ static final String dbPath = "."; /*"db";*/
+ // configPath --> stores masters config file
+ static final String configPath = "."; /*"config";*/
+ static final String mastersFilename = "masters";
+ static final String logsPath = "."; /*"logs";*/
+ static final String accessFilename = "access";
+
+ // Maximum time (in milliseconds) without update being read from the master: 60 s
+ static final int MAX_IDLE_TIME = 60000;
+
+ // ECL "draft" mode -- Initial changeNumber
+ static final int INITIAL_CHANGENUMBER = 1;
+ // ECL "opends" mode -- Initial control value:
+ // --control "1.3.6.1.4.1.26027.1.5.4:false:;" ==> first cookie: ";"
+ static final String INITIAL_COOKIE = ";";
+
+
+ static PrintWriter standardOut = null;
+ static PrintWriter accessOut = null;
+ static HashMap<String,CSN> RUV;
+ static Object lock;
+ static HashMap<String,File> files;
+ static int nb_ops = 0;
+ static int total_nb_ops = 0;
+ static int nb_ignored = 0;
+ static int changeNumber = 0;
+ static int lastChangeNumber = 0;
+ static String changelogCookie = null;
+ static String lastExternalChangelogCookie = null;
+ static int missingChanges = 0;
+ static int lastMissingChanges = 1;
+
+ static String eclMode = null;
+ static int queueSize = 0;
+ static String bindDn = null;
+ static String bindPwd = null;
+ static boolean displayMissingChanges = false;
+ static String outputFilename = null;
+
+ public static void main( String[] args )
+
+ {
+
+
+ FileWriter out = null;
+
+ files = new HashMap<String,File>();
+
+ // Load latest read CSN values from files in db/ directory
+ File csnDir = new File(dbPath);
+ RUV = new HashMap<String,CSN>();
+ try {
+ FilenameFilter csnFileFilter = new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".csn");
+ }
+ };
+ File[] csnFiles = csnDir.listFiles(csnFileFilter);
+ if ( csnFiles != null ) {
+ for (File f: csnFiles) {
+ String csnFilename = f.getName();
+ String id =
+ csnFilename.substring(0, csnFilename.indexOf(".csn"));
+ BufferedReader in = new BufferedReader (new FileReader(f));
+ CSN mycsn = new CSN(in.readLine());
+ if ( mycsn.value == null )
+ mycsn = new CSN("00000000000000000000");
+ // System.out.println(files[i] + "\t" + mycsn);
+ RUV.put(id, mycsn);
+
+ files.put(id, f);
+ }
+ }
+ } catch (IOException e) {
+ println("ERROR", e.toString());
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+
+ /********** Parse arguments **********/
+ int masterN=0;
+ String hostport = null;
+ ArrayList<Server> masters = new ArrayList<Server>();
+
+ for (int k = 0; k < args.length; k++) {
+ String opt = args[k];
+ String val = args[k+1];
+
+ // ECL mode: "opends" or "draft"
+ if (opt.equals("-m")) {
+ eclMode = val;
+ }
+
+ // Queue size
+ if (opt.equals("-q")) {
+ queueSize = Integer.parseInt(val);
+ }
+
+ // Display missing changes?
+ if (opt.equals("-x")) {
+ if ( val.equals("true") )
+ displayMissingChanges = true;
+ else
+ displayMissingChanges = false;
+ }
+
+ // Bind DN
+ if (opt.equals("-D")) {
+ bindDn = val;
+ System.out.println(".......... bindDN: " + bindDn);
+ }
+
+ // Bind password
+ if (opt.equals("-w")) {
+ bindPwd = val;
+ System.out.println(".......... bindPwd: " + bindPwd);
+ }
+
+
+ // Stand-alone server:port
+ if (opt.equals("-s")) {
+ hostport = val;
+ System.out.println(".......... stand-alone server: " + hostport);
+ }
+
+
+ // Replicated masters
+ if (opt.equals("-p")) {
+ masters.add(new Server(val));
+ }
+
+
+ // Standard output file
+ if (opt.equals("-o")) {
+ outputFilename = val;
+ }
+
+ k++;
+ } /* for() */
+
+
+ if ( eclMode == null || queueSize == 0 || bindDn == null ||
+ bindPwd == null || hostport == null || masters.size() == 0 ||
+ outputFilename == null ) {
+ System.out.println("usage: -m {draft|opends} -q {queue size} "
+ + "-x {(displayMissingChanges):true|false} "
+ + "-o {outputFilename} -D {bindD} -w {bindPwd} "
+ + "-s {standalone-host:port} "
+ + "-p {master1-host:port} "
+ + "-p {master2-host:port}...");
+ System.exit(1);
+ }
+
+ /* try {
+ File mastersFile= new File(configPath, mastersFilename);
+ LineNumberReader in=new LineNumberReader (new FileReader(mastersFile) );
+ String line;
+ while ( in.ready() ) {
+ line=in.readLine();
+ masters.add(new Server(line));
+ }
+ } catch (IOException e) {
+ println ("ERROR", e.toString());
+ System.exit(1);
+ } */
+
+ masters.trimToSize();
+ // System.out.println(masters);
+
+ /*************************************/
+
+
+ // Output file (logs are appended)
+ try {
+ standardOut = new PrintWriter(new BufferedWriter(new FileWriter( new File(outputFilename)) ) );
+ } catch (IOException e) {
+ println ("ERROR", e.toString() );
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+
+ // Access log (data is appended)
+ try {
+ accessOut = new PrintWriter(new BufferedWriter(new FileWriter( new File(logsPath, accessFilename)) ) );
+ } catch (IOException e) {
+ println ("ERROR", e.toString() );
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+
+
+
+ /********** Initialise reader/writer threads **********/
+ // Create a bounded blocking queue of integers
+ BlockingQueue<Change> queue = new ArrayBlockingQueue<Change>(queueSize);
+
+ // Initialise reader thread --> read updates from replicated master
+ Reader reader = new Reader(queue, masters);
+ reader.start();
+
+ // Initialise writer thread --> write updates onto stand-alone server
+ Writer writer = new Writer(queue, hostport);
+ writer.start();
+
+ lock = new Object();
+ synchronized (lock) {
+ try {
+ lock.wait();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ long start = System.currentTimeMillis();
+ int i=0;
+ while (true) {
+ int loopPeriod = 10; /* 10 s */
+ sleep(loopPeriod * 1000);
+ total_nb_ops += nb_ops;
+ long duration = ((System.currentTimeMillis() - start)/1000);
+ println("INFO", "Replayed " + nb_ops/loopPeriod
+ + " ops/sec. (Avg = " + (total_nb_ops/duration)
+ + " ops/s, Total = " + total_nb_ops
+ + " , ignored = " + nb_ignored + " )");
+ nb_ops = 0;
+ if ( i++ == 3 && displayMissingChanges == true ) {
+ if ( eclMode.equals("draft") ) {
+ missingChanges = lastChangeNumber - changeNumber;
+ float percentage = (lastMissingChanges - missingChanges);
+ println("INFO", "Current changeNumber = " + changeNumber
+ + ", lastChangeNumber = " + lastChangeNumber
+ + ", missing changes = " + missingChanges + "/"
+ + lastMissingChanges + " (" + percentage + ")");
+ lastMissingChanges = missingChanges;
+ if (lastMissingChanges == 0)
+ lastMissingChanges = 1;
+ } else if ( eclMode.equals("opends") ) {
+ println("INFO", "Current changelogCookie = "
+ + changelogCookie
+ + ", lastExternalChangelogCookie = "
+ + lastExternalChangelogCookie);
+ }
+ i = 0;
+ }
+ }
+
+ }
+
+ public static void inc_ops(int c) {
+ nb_ops++;
+ changeNumber = c;
+ }
+
+ public static void inc_ops(String c) {
+ nb_ops++;
+ changelogCookie = c;
+ }
+
+ public static void inc_ignored(int c) {
+ nb_ignored++;
+ changeNumber = c;
+ }
+
+ public static void inc_ignored(String c) {
+ nb_ignored++;
+ changelogCookie = c;
+ }
+
+ public static String getDate() {
+
+ // Initialize the today's date string
+ String DATE_FORMAT = "yyyy/MM/dd:HH:mm:ss";
+ java.text.SimpleDateFormat sdf =
+ new java.text.SimpleDateFormat(DATE_FORMAT);
+ Calendar c1 = Calendar.getInstance(); // today
+ return("[" + sdf.format(c1.getTime()) + "]");
+ }
+
+ public static void println(String level, String msg) {
+ standardOut.println (getDate() + " - " + level + ": " + msg );
+ }
+
+ public static void sleep(int time) {
+ try {
+ Thread.sleep(time);
+ }
+ catch ( InterruptedException e )
+ {
+ println( "ERROR" , e.toString() );
+ }
+ }
+}
diff --git a/opends/tests/staf-tests/shared/java/ldapjdk/ImprovedLDAPConnection.java b/opends/tests/staf-tests/shared/java/ldapjdk/ImprovedLDAPConnection.java
new file mode 100644
index 0000000..5932d52
--- /dev/null
+++ b/opends/tests/staf-tests/shared/java/ldapjdk/ImprovedLDAPConnection.java
@@ -0,0 +1,200 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2010 Sun Microsystems, Inc.
+ */
+
+import netscape.ldap.*;
+import netscape.ldap.util.*;
+import java.util.*;
+import java.io.*;
+
+public class ImprovedLDAPConnection extends LDAPConnection {
+
+ public ImprovedLDAPConnection() {
+ super();
+ }
+
+ public void apply (Change change) {
+
+ for (String mychange: change.changes) {
+ String mytype = null;
+ // Parse LDIF content
+ ByteArrayInputStream stream = new ByteArrayInputStream(mychange.getBytes());
+ LDIF ldif = null;
+ try {
+ ldif = new LDIF(new DataInputStream(stream));
+ LDIFContent content = ldif.nextRecord().getContent();
+
+ //EclReadAndPlay.println ("DEBUG", "\n\nWriting the following update: \n" + content.toString() );
+ switch (content.getType()) {
+ case LDIFContent.ADD_CONTENT:
+ mytype = "ADD";
+ content = ( LDIFAddContent ) content;
+
+ LDAPAttributeSet attrSet = new LDAPAttributeSet( ((LDIFAddContent)content).getAttributes());
+ // remove non-user-modifiable attributes:
+ // entryuuid, pwdchangedtime, creatorsname, createtimestamp
+ LDAPAttribute entryuuidAttr = attrSet.getAttribute("entryuuid");
+ if ( entryuuidAttr != null ) {
+ attrSet.remove("entryuuid");
+ }
+ LDAPAttribute pwdchangedAttr = attrSet.getAttribute("pwdChangedTime");
+ if ( entryuuidAttr != null ) {
+ attrSet.remove("pwdchangedtime");
+ }
+ LDAPAttribute creatorAttr = attrSet.getAttribute("creatorsname");
+ if ( creatorAttr != null ) {
+ attrSet.remove("creatorsname");
+ }
+ LDAPAttribute createtimeAttr = attrSet.getAttribute("createtimestamp");
+ if ( createtimeAttr != null ) {
+ attrSet.remove("createtimestamp");
+ }
+ LDAPEntry addEntry = new LDAPEntry ( change.dn, attrSet );
+ //EclReadAndPlay.println ("INFO", "********************* Entry: ************** \n" + addEntry + "\n******************\n" );
+ try {
+ this.add( addEntry );
+ }
+ catch( LDAPException e ) {
+ EclReadAndPlay.println("ERROR", "Cannot add entry \"" + change.dn + "\" (csn="
+ + change.csn + ")" );
+ EclReadAndPlay.println("ERROR", e.toString() );
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ // replace the unique id
+// LDAPAttribute myAttr = new LDAPAttribute ("nsuniqueid", change.nsUniqueId);
+// LDAPAttribute myAttr = new LDAPAttribute ("entryuuid", change.nsUniqueId);
+// LDAPModification mod = new LDAPModification ( LDAPModification.REPLACE, myAttr );
+// try {
+// this.modify( change.dn, mod );
+// }
+// catch( LDAPException e ) {
+// EclReadAndPlay.println ("ERROR", "Cannot modify nsuniqueid of entry \""
+// + change.dn + "\" (csn=" + change.csn + ")" );
+// EclReadAndPlay.println ("ERROR", e.toString() );
+// System.exit(1);
+// }
+ //System.out.EclReadAndPlay.println( addEntry);
+ break;
+ case LDIFContent.MODIFICATION_CONTENT:
+ mytype="MOD";
+ LDAPModification[] mods = ((LDIFModifyContent)content).getModifications();
+ // remove modifiersname and modifytimestamp mods
+ boolean[] deleteItem = new boolean[mods.length];
+ int size = 0;
+ for (int i = 0 ; i < mods.length ; i++) {
+ LDAPAttribute modAttr = mods[i].getAttribute();
+ if ( modAttr.getBaseName().equalsIgnoreCase("modifiersname") ||
+ modAttr.getBaseName().equalsIgnoreCase("modifytimestamp") ) {
+ // remove mods[i] from mods
+ deleteItem[i] = true;
+ } else {
+ deleteItem[i] = false;
+ size++;
+ }
+ }
+ LDAPModification[] realMods = new LDAPModification[size];
+ int index = 0;
+ for (int i = 0 ; i < mods.length ; i++) {
+ if ( !deleteItem[i] ) {
+ realMods[index++] = mods[i];
+ }
+ }
+ try {
+ this.modify( change.dn, realMods );
+ }
+ catch( LDAPException e ) {
+ EclReadAndPlay.println("ERROR", "Cannot modify entry \"" + change.dn
+ + "\" (csn=" + change.csn + ")" );
+ EclReadAndPlay.println("DEBUG", "mods\"" + mods + "\"" );
+ EclReadAndPlay.println("ERROR", e.toString() );
+ e.printStackTrace();
+ System.exit(1);
+ }
+ break;
+ case LDIFContent.MODDN_CONTENT:
+ if ( change.newRDN == null ) { // => fixOP MODRDN
+ change.newRDN=((LDIFModDNContent)content).getRDN();
+ change.deleteOldRDN=((LDIFModDNContent)content).getDeleteOldRDN();
+ change.newSuperior=((LDIFModDNContent)content).getNewParent();
+ }
+
+
+ try {
+ if (change.newSuperior == null ) {
+ mytype="MODRDN";
+ this.rename( change.dn, change.newRDN, change.deleteOldRDN );
+ }
+ else {
+ mytype="MODDN";
+ this.rename( change.dn, change.newRDN, change.newSuperior, change.deleteOldRDN );
+ }
+ }
+ catch( LDAPException e ) {
+ EclReadAndPlay.println( "ERROR", "Cannot rename entry \"" + change.dn
+ + "\" (csn=" + change.csn + ")" );
+ EclReadAndPlay.println( "ERROR", "newRDN =\"" + change.newRDN
+ + "\" (deleteOldRDN=" + change.deleteOldRDN + ")" );
+ EclReadAndPlay.println( "ERROR", "change =\"" + mychange + ")" );
+ EclReadAndPlay.println( "ERROR", e.toString());
+ e.printStackTrace();
+ System.exit(1);
+ }
+ break;
+ case LDIFContent.DELETE_CONTENT:
+ mytype="DEL";
+ try {
+ this.delete( change.dn );
+ }
+ catch( LDAPException e ) {
+ EclReadAndPlay.println ("ERROR", "Cannot delete entry \"" + change.dn
+ + "\" (csn=" + change.csn + ")" );
+ EclReadAndPlay.println( "ERROR", e.toString() );
+ e.printStackTrace();
+ System.exit(1);
+ }
+ break;
+ default:
+ EclReadAndPlay.println("ERROR", "Cannot parse change (type=" + content.getType()
+ + "):\n" + mychange + "_");
+ mytype="Unknown";
+ break;
+ }
+
+ } catch ( IOException e ) {
+ EclReadAndPlay.println( "ERROR" , e.toString() );
+ e.printStackTrace();
+ EclReadAndPlay.println( "ERROR" , change.toString() );
+ }
+ EclReadAndPlay.accessOut.println(EclReadAndPlay.getDate() + "- INFO: " + mytype + " \"" + change.dn
+ + "\" (" + change.csn +" / " + change.changeNumber + ")" );
+ }
+ }
+
+}
+
+
diff --git a/opends/tests/staf-tests/shared/java/ldapjdk/LDIF.java b/opends/tests/staf-tests/shared/java/ldapjdk/LDIF.java
new file mode 100644
index 0000000..975a385
--- /dev/null
+++ b/opends/tests/staf-tests/shared/java/ldapjdk/LDIF.java
@@ -0,0 +1,798 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2010 Sun Microsystems, Inc.
+ */
+
+import netscape.ldap.util.*;
+
+import java.util.*;
+import netscape.ldap.*;
+import netscape.ldap.client.*;
+import java.io.*;
+import java.net.*;
+
+/**
+ * LDAP Data Interchange Format (LDIF) is a file format used to
+ * import and export directory data from an LDAP server and to
+ * describe a set of changes to be applied to data in a directory.
+ * This format is described in the Internet draft
+ * <A HREF="ftp://ftp.ietf.org/internet-drafts/draft-good-ldap-ldif-00.txt"
+ * TARGET="_blank">The LDAP Data Interchange Format (LDIF) -
+ * Technical Specification</A>.
+ * <P>
+ *
+ * This class implements an LDIF file parser. You can construct
+ * an object of this class to parse data in LDIF format and
+ * manipulate the data as individual <CODE>LDIFRecord</CODE> objects.
+ * <P>
+ *
+ * @version 1.0
+ * @see netscape.ldap.util.LDIFRecord
+ */
+public class LDIF implements Serializable {
+
+ /**
+ * Internal constants
+ */
+ private final static char COMMENT = '#';
+ static final long serialVersionUID = -2710382547996750924L;
+
+ /**
+ * Constructs an <CODE>LDIF</CODE> object to parse the
+ * LDAP data read from stdin.
+ * @exception IOException An I/O error has occurred.
+ */
+ public LDIF() throws IOException {
+ DataInputStream ds = new DataInputStream(System.in);
+ BufferedReader d = new BufferedReader(new InputStreamReader(ds, "UTF8"));
+ m_reader = new LineReader(d);
+ m_source = "System.in";
+ m_decoder = new MimeBase64Decoder();
+ }
+
+ /**
+ * Constructs an <CODE>LDIF</CODE> object to parse the
+ * LDIF data read from a specified file.
+ * @param file the name of the LDIF file to parse
+ * @exception IOException An I/O error has occurred.
+ */
+ public LDIF(String file) throws IOException {
+ FileInputStream fs = new FileInputStream(file);
+ DataInputStream ds = new DataInputStream(fs);
+ BufferedReader d = new BufferedReader(new InputStreamReader(ds, "UTF8"));
+ m_reader = new LineReader(d);
+ m_source = file;
+ m_decoder = new MimeBase64Decoder();
+ }
+
+ /**
+ * Constructs an <CODE>LDIF</CODE> object to parse the
+ * LDIF data read from an input stream.
+ * @param dstThe input stream providing the LDIF data
+ * @exception IOException An I/O error has occurred.
+ */
+ public LDIF(DataInputStream ds) throws IOException {
+ BufferedReader d = new BufferedReader(new InputStreamReader(ds, "UTF8"));
+ m_reader = new LineReader(d);
+ m_source = ds.toString();
+ m_decoder = new MimeBase64Decoder();
+ }
+
+ /**
+ * Returns the next record in the LDIF data. You can call this
+ * method repeatedly to iterate through all records in the LDIF data.
+ * <P>
+ *
+ * @return the next record as an <CODE>LDIFRecord</CODE>
+ * object or null if there are no more records.
+ * @exception IOException An I/O error has occurred.
+ * @see netscape.ldap.util.LDIFRecord
+ */
+ public LDIFRecord nextRecord() throws IOException {
+ if ( m_done )
+ return null;
+ else
+ return parse_ldif_record( m_reader );
+ }
+
+ /**
+ * Parses ldif content. The list of attributes is
+ * terminated by \r\n or '-'. This function is
+ * also used to parse the attributes in modifications.
+ * @param ds data input stream
+ */
+ private LDIFRecord parse_ldif_record(LineReader d)
+ throws IOException {
+ String line = null;
+ String dn = null;
+ Vector attrs = new Vector();
+ LDIFRecord rec = null;
+
+ // Skip past any blank lines
+ while( ((line = d.readLine()) != null) &&
+ (line.length() < 1) ) {
+ }
+ if (line == null) {
+ return null;
+ }
+
+ if (line.toLowerCase().startsWith("version:")) {
+ m_version = Integer.parseInt(
+ line.substring("version:".length()).trim() );
+ if ( m_version != 1 ) {
+ throwLDIFException( "Unexpected " + line );
+ }
+ // Do the next record
+ line = d.readLine();
+ if ( (line != null) && (line.length() == 0) ) {
+ // Skip the newline
+ line = d.readLine();
+ }
+ if (line == null) {
+ return null;
+ }
+ }
+
+ if (!line.toLowerCase().startsWith("dn:"))
+ throwLDIFException("expecting dn:");
+ dn = line.substring(3).trim();
+ if (dn.startsWith(":") && (dn.length() > 1)) {
+ String substr = dn.substring(1).trim();
+ dn = new String(getDecodedBytes(substr), "UTF8");
+ }
+
+ LDIFContent content = parse_ldif_content(d);
+ rec = new LDIFRecord(dn, content);
+ return rec;
+ }
+
+ /**
+ * Parses ldif content. The list of attributes is
+ * terminated by \r\n or '-'. This function is
+ * also used to parse the attributes in modifications.
+ * @param ds data input stream
+ */
+ private LDIFContent parse_ldif_content(LineReader d)
+ throws IOException {
+ String line = d.readLine();
+ if ((line == null) || (line.length() < 1) || (line.equals("-"))) {
+ // if this is empty line, then we're finished reading all
+ // the info for the current entry
+ if ((line != null) && (line.length() < 1)) {
+ m_currEntryDone = true;
+ }
+ return null;
+ }
+
+ if (line.toLowerCase().startsWith("changetype:")) {
+ /* handles (changerecord) */
+ LDIFContent lc = null;
+ String changetype = line.substring(11).trim();
+ if (changetype.equals("modify")) {
+ lc = parse_mod_spec(d);
+ } else if (changetype.equals("add")) {
+ lc = parse_add_spec(d);
+ } else if (changetype.equals("delete")) {
+ lc = parse_delete_spec(d);
+ } else if (changetype.equals("moddn") ||
+ changetype.equals("modrdn")) {
+ lc = parse_moddn_spec(d);
+ } else {
+ throwLDIFException("change type not supported");
+ }
+ return lc;
+ }
+
+ /* handles 1*(attrval-spec) */
+ Hashtable ht = new Hashtable();
+ String newtype = null;
+ Object val = null;
+ LDAPAttribute newAttr = null;
+ Vector controlVector = null;
+
+ /* Read lines until we're past the record */
+ while( true ) {
+ if (line.toLowerCase().startsWith("control:")) {
+ if ( controlVector == null ) {
+ controlVector = new Vector();
+ }
+ controlVector.addElement( parse_control_spec( line ) );
+ } else {
+ /* An attribute */
+ int len = line.length();
+ if ( len < 1 ) {
+ break;
+ }
+ int idx = line.indexOf(':');
+ /* Must have a colon */
+ if (idx == -1)
+ throwLDIFException("no ':' found");
+ /* attribute type */
+ newtype = line.substring(0,idx).toLowerCase();
+ val = "";
+ /* Could be :: for binary */
+ idx++;
+ if ( len > idx ) {
+ if ( line.charAt(idx) == ':' ) {
+ idx++;
+ String substr = line.substring(idx).trim();
+ val = getDecodedBytes(substr);
+ } else if (line.charAt(idx) == '<') {
+ try {
+ URL url =
+ new URL(line.substring(idx+1).trim());
+ String filename = url.getFile();
+ val = getFileContent(filename);
+ } catch (MalformedURLException ex) {
+ throwLDIFException(
+ ex +
+ ": cannot construct url "+
+ line.substring(idx+1).trim());
+ }
+ } else {
+ val = line.substring(idx).trim();
+ }
+ }
+ /* Is there a previous value for this attribute? */
+ newAttr = (LDAPAttribute)ht.get( newtype );
+ if ( newAttr == null ) {
+ newAttr = new LDAPAttribute( newtype );
+ }
+ if ( val instanceof String ) {
+ newAttr.addValue( (String)val );
+ } else {
+ newAttr.addValue( (byte[])val );
+ }
+ ht.put( newtype, newAttr );
+ }
+ line = d.readLine();
+ if (line == null || (line.length() < 1) ||
+ (line.equals("-"))) {
+ if ((line != null) && (line.length() < 1)) {
+ m_currEntryDone = true;
+ }
+ break;
+ }
+ }
+ LDIFAttributeContent ac = new LDIFAttributeContent();
+ // Copy over the attributes to the record
+ Enumeration en = ht.elements();
+ while( en.hasMoreElements() ) {
+ ac.addElement( (LDAPAttribute)en.nextElement() );
+ }
+ ht.clear();
+ if( controlVector != null ) {
+ LDAPControl[] controls =
+ new LDAPControl[controlVector.size()];
+ controlVector.copyInto( controls );
+ ac.setControls( controls );
+ controlVector.removeAllElements();
+ }
+ return ac;
+ }
+
+ private byte[] getDecodedBytes(String line) {
+ ByteBuf inBuf = new ByteBuf(line);
+ ByteBuf decodedBuf = new ByteBuf();
+ /* Translate from base 64 */
+ m_decoder.translate( inBuf, decodedBuf );
+ return decodedBuf.toBytes();
+ }
+
+ private byte[] getFileContent(String url) throws IOException {
+ StringTokenizer tokenizer = new StringTokenizer(url, "|");
+ String filename = url;
+ int num = tokenizer.countTokens();
+ if (num == 2) {
+ String token = (String)tokenizer.nextElement();
+ int index = token.lastIndexOf("/");
+ String drive = token.substring(index+1);
+ token = (String)tokenizer.nextElement();
+ token = token.replace('/', '\\');
+ filename = drive+":"+token;
+ }
+
+ File file = new File(filename);
+ byte[] b = new byte[(int)file.length()];
+ FileInputStream fi = new FileInputStream(filename);
+ fi.read(b);
+ return b;
+ }
+
+ /**
+ * Parses add content
+ * @param ds data input stream
+ */
+ private LDIFAddContent parse_add_spec(LineReader d)
+ throws IOException {
+ LDIFAttributeContent ac = (LDIFAttributeContent)parse_ldif_content(d);
+ if (m_currEntryDone)
+ m_currEntryDone = false;
+ LDAPAttribute attrs[] = ac.getAttributes();
+ LDIFAddContent rc = new LDIFAddContent(attrs);
+ LDAPControl[] controls = ac.getControls();
+ if ( controls != null ) {
+ rc.setControls( controls );
+ }
+ return rc;
+ }
+
+ /**
+ * Parses delete content
+ * @param ds data input stream
+ */
+ private LDIFDeleteContent parse_delete_spec(LineReader d)
+ throws IOException {
+ Vector controlVector = null;
+ LDIFDeleteContent dc = new LDIFDeleteContent();
+ String line = d.readLine();
+ while( line != null && !line.equals("") ) {
+ if (line.toLowerCase().startsWith("control:")) {
+ if ( controlVector == null ) {
+ controlVector = new Vector();
+ }
+ controlVector.addElement( parse_control_spec( line ) );
+ } else {
+ throwLDIFException("invalid SEP" );
+ }
+ line = d.readLine();
+ }
+ if( controlVector != null ) {
+ LDAPControl[] controls = new LDAPControl[controlVector.size()];
+ controlVector.copyInto( controls );
+ dc.setControls( controls );
+ controlVector.removeAllElements();
+ }
+
+ return dc;
+ }
+
+ /**
+ * Parses change modification.
+ * @param ds data input stream
+ */
+ private LDIFModifyContent parse_mod_spec(LineReader d)
+ throws IOException {
+
+ Vector controlVector = null;
+ String line = null;
+ line = d.readLine();
+ LDIFModifyContent mc = new LDIFModifyContent();
+ do {
+ int oper = -1;
+ if (line.toLowerCase().startsWith("add:")) {
+ oper = LDAPModification.ADD;
+ } else if (line.toLowerCase().startsWith("delete:")) {
+ oper = LDAPModification.DELETE;
+ } else if (line.toLowerCase().startsWith("replace:")) {
+ oper = LDAPModification.REPLACE;
+ } else
+ throwLDIFException("unknown modify type");
+
+ LDIFAttributeContent ac =
+ (LDIFAttributeContent)parse_ldif_content(d);
+ if (ac != null) {
+ LDAPAttribute attrs[] = ac.getAttributes();
+ for (int i = 0; i < attrs.length; i++) {
+ LDAPModification mod = new LDAPModification(oper, attrs[i]);
+ mc.addElement( mod );
+ }
+ LDAPControl[] controls = ac.getControls();
+ if ( controls != null ) {
+ if ( controlVector == null ) {
+ controlVector = new Vector();
+ }
+ for( int i = 0; i < controls.length; i++ ) {
+ controlVector.addElement( controls[i] );
+ }
+ }
+ // if there is no attrval-spec, go into the else statement
+ } else {
+ int index = line.indexOf(":");
+ if (index == -1)
+ throwLDIFException("colon missing in "+line);
+
+ String attrName = line.substring(index+1).trim();
+
+ if (oper == LDAPModification.ADD)
+ throwLDIFException("add operation needs the value for attribute "+attrName);
+ LDAPAttribute attr = new LDAPAttribute(attrName);
+ LDAPModification mod = new LDAPModification(oper, attr);
+ mc.addElement(mod);
+ }
+ if (m_currEntryDone) {
+ m_currEntryDone = false;
+ break;
+ }
+ line = d.readLine();
+ } while (line != null && !line.equals(""));
+
+ if( controlVector != null ) {
+ LDAPControl[] controls = new LDAPControl[controlVector.size()];
+ controlVector.copyInto( controls );
+ mc.setControls( controls );
+ controlVector.removeAllElements();
+ }
+ return mc;
+ }
+
+ /**
+ * Parses moddn/modrdn modification.
+ * @param d data input stream
+ */
+ private LDIFModDNContent parse_moddn_spec(LineReader d)
+ throws IOException {
+ Vector controlVector = null;
+ String line = null;
+ line = d.readLine();
+ LDIFModDNContent mc = new LDIFModDNContent();
+ String val = null;
+ do {
+ if (line.toLowerCase().startsWith("newrdn:") &&
+ (line.length() > ("newrdn:".length()+1))) {
+ mc.setRDN(line.substring("newrdn:".length()).trim());
+ } else if (line.toLowerCase().startsWith("deleteoldrdn:") &&
+ (line.length() > ("deleteoldrdn:".length()+1))) {
+ String str = line.substring("deleteoldrdn:".length()).trim();
+ if (str.equals("0") || str.equalsIgnoreCase("false"))
+ mc.setDeleteOldRDN(false);
+ else if (str.equals("1") || str.equalsIgnoreCase("true"))
+ mc.setDeleteOldRDN(true);
+ else
+ throwLDIFException("Incorrect input for deleteOldRdn ");
+ } else if (line.toLowerCase().startsWith("newsuperior:") &&
+ (line.length() > ("newsuperior:".length()+1))) {
+ mc.setNewParent(line.substring(
+ "newsuperior:".length()).trim());
+ } else if (line.toLowerCase().startsWith("newparent:") &&
+ (line.length() > ("newparent:".length()+1))) {
+ mc.setNewParent(line.substring(
+ "newparent:".length()).trim());
+ } else if (line.toLowerCase().startsWith("control:")) {
+ if ( controlVector == null ) {
+ controlVector = new Vector();
+ }
+ controlVector.addElement( parse_control_spec( line ) );
+ }
+ line = d.readLine();
+ } while (line != null && !line.equals(""));
+
+ if( controlVector != null ) {
+ LDAPControl[] controls = new LDAPControl[controlVector.size()];
+ controlVector.copyInto( controls );
+ mc.setControls( controls );
+ controlVector.removeAllElements();
+ }
+
+ return mc;
+ }
+
+ /**
+ * Parses the specification of a control<BR>
+ *
+ * A control looks line one of the following:
+ *<BR>
+ * control: 1.2.3.4.10.210
+ *<BR>
+ * control: 1.2.3.4.10.210 true
+ *<BR>
+ * control: 1.2.3.4.10.210 true: someASCIIvalue
+ *<BR>
+ * control: 1.2.3.4.10.210: someASCIIvalue
+ *<BR>
+ * control: 1.2.3.4.10.210 true:: 44GK44GM44GV44KP44KJ
+ *<BR>
+ * control: 1.2.3.4.10.210:: 44GK44GM44GV44KP44KJ
+ *<BR>
+ * control: 1.2.3.4.10.210 true:< file:///usr/local/directory/cont.dta
+ *<BR>
+ * control: 1.2.3.4.10.210:< file:///usr/local/directory/cont.dta
+ *
+ * @param line a line containing a control spec
+ * @return a parsed control.
+ * @exception IOException if the line could not be parsed
+ */
+ protected LDAPControl parse_control_spec( String line )
+ throws IOException {
+ boolean criticality = true;
+ String OID;
+ byte[] val = null;
+ int len = line.length();
+ int idx = line.indexOf(':') + 2;
+ /* OID, must be present */
+ if ( idx >= len ) {
+ throwLDIFException("OID required for control");
+ }
+ line = line.substring(idx).trim();
+ idx = line.indexOf(' ');
+ if ( idx < 0 ) {
+ OID = line;
+ } else {
+ /* Optional criticality */
+ OID = line.substring(0, idx);
+ line = line.substring(idx+1);
+ idx = line.indexOf(':');
+ String criticalVal;
+ if (idx > 0) {
+ criticalVal = line.substring(0, idx);
+ } else {
+ criticalVal = line;
+ }
+ if ( criticalVal.compareTo("true") == 0 ) {
+ criticality = true;
+ } else if ( criticalVal.compareTo("false") == 0 ) {
+ criticality = false;
+ } else {
+ throwLDIFException(
+ "Criticality for control must be true" +
+ " or false, not " + criticalVal);
+ }
+ /* Optional value */
+ if ( idx > 0 ) {
+ /* Could be :: for binary */
+ idx++;
+ if ( line.length() > idx ) {
+ if ( line.charAt(idx) == ':' ) {
+ idx++;
+ line = line.substring(idx).trim();
+ val = getDecodedBytes(line);
+ } else if (line.charAt(idx) == '<') {
+ String urlString = line.substring(idx+1).trim();
+ try {
+ URL url = new URL(urlString);
+ String filename = url.getFile();
+ val = getFileContent(filename);
+ } catch (MalformedURLException ex) {
+ throwLDIFException(
+ ex + ": cannot construct url "+
+ urlString);
+ }
+ } else {
+ try {
+ val = line.substring(idx).trim().getBytes("UTF8");
+ } catch(Exception x) {
+ }
+ }
+ }
+ }
+ }
+ return new LDAPControl( OID, criticality, val );
+ }
+
+ /**
+ * Returns true if all the bytes in the given array are valid for output as a
+ * String according to the LDIF specification. If not, the array should
+ * output base64-encoded.
+ * @return <code>true</code> if all the bytes in the given array are valid for
+ * output as a String according to the LDIF specification; otherwise,
+ * <code>false</code>.
+ */
+ public static boolean isPrintable(byte[] b) {
+ for( int i = b.length - 1; i >= 0; i-- ) {
+ if ( (b[i] < ' ') || (b[i] > 127) ) {
+ if ( b[i] != '\t' )
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Outputs the String in LDIF line-continuation format. No line will be longer
+ * than the given max. A continuation line starts with a single blank space.
+ * @param pw the printer writer
+ * @param value the given string being printed out
+ * @param max the maximum characters allowed in the line
+ */
+ public static void breakString( PrintWriter pw, String value, int max) {
+ int leftToGo = value.length();
+ int written = 0;
+ int maxChars = max;
+ /* Limit to 77 characters per line */
+ while( leftToGo > 0 ) {
+ int toWrite = Math.min( maxChars, leftToGo );
+ String s = value.substring( written, written+toWrite);
+ if ( written != 0 ) {
+ pw.print( " " + s );
+ } else {
+ pw.print( s );
+ maxChars -= 1;
+ }
+ written += toWrite;
+ leftToGo -= toWrite;
+ /* Don't use pw.println, because it outputs an extra CR
+ in Win32 */
+ pw.print( '\n' );
+ }
+ }
+
+ /**
+ * Gets the version of LDIF used in the data.
+ * @return version of LDIF used in the data.
+ */
+ public int getVersion() {
+ return m_version;
+ }
+
+ /**
+ * Gets the string representation of the
+ * entire LDIF file.
+ * @return the string representation of the entire LDIF data file.
+ */
+ public String toString() {
+ return "LDIF {" + m_source + "}";
+ }
+
+ /**
+ * Throws a LDIF file exception including the current line number.
+ * @param msg Error message
+ */
+ protected void throwLDIFException(String msg)throws IOException {
+ throw new IOException ("line " +
+ (m_currLineNum-m_continuationLength) + ": " + msg);
+ }
+
+ /**
+ * Internal variables
+ */
+ private int m_version = 1;
+ private boolean m_done = false;
+ private LineReader m_reader = null;
+ private String m_source = null;
+ private MimeBase64Decoder m_decoder = null;
+ private boolean m_currEntryDone = false;
+ private int m_currLineNum;
+ private int m_continuationLength;
+
+ /* Concatenate continuation lines, if present */
+ class LineReader {
+ LineReader( BufferedReader d ) {
+ _d = d;
+ }
+ /**
+ * Reads a non-comment line.
+ * @return a string or null.
+ */
+ String readLine() throws IOException {
+ String line = null;
+ String result = null;
+ int readCnt = 0, continuationLength = 0;
+ do {
+ /* Leftover line from last time? */
+ if ( _next != null ) {
+ line = _next;
+ _next = null;
+ } else {
+ line = _d.readLine();
+ }
+ if (line != null) {
+ readCnt++;
+ /* Empty line means end of record */
+ if( line.length() < 1 ) {
+ if ( result == null )
+ result = line;
+ else {
+ _next = line;
+ break;
+ }
+ } else if( line.charAt(0) == COMMENT ) {
+ /* Ignore comment lines */
+ } else if( line.charAt(0) != ' ' ) {
+ /* Not a continuation line */
+ if( result == null ) {
+ result = line;
+ } else {
+ _next = line;
+ break;
+ }
+ } else {
+ /* Continuation line */
+ if ( result == null ) {
+ m_currLineNum += readCnt;
+ throwLDIFException("continuation out of nowhere");
+ }
+ result += line.substring(1);
+ continuationLength++;
+ }
+ } else {
+ /* End of file */
+ break;
+ }
+ } while ( true );
+
+ m_done = ( line == null );
+
+ m_currLineNum += readCnt;
+ if (_next != null) {
+ // read one line ahead
+ m_currLineNum--;
+ }
+ m_continuationLength = continuationLength;
+
+ return result;
+ }
+ private BufferedReader _d;
+ String _next = null;
+ }
+
+ /**
+ * Converts a byte array to a printable string following
+ * the LDIF rules (encode in base64 if necessary)
+ *
+ * @param b the byte array to convert
+ * @return a converted string which is printable.
+ */
+ public static String toPrintableString( byte[] b ) {
+ String s = "";
+ if (isPrintable(b)) {
+ try {
+ s = new String(b, "UTF8");
+ } catch ( java.io.UnsupportedEncodingException e ) {
+ }
+ } else {
+ ByteBuf inBuf = new ByteBuf( b, 0, b.length );
+ ByteBuf encodedBuf = new ByteBuf();
+ // Translate to base 64
+ MimeBase64Encoder encoder = new MimeBase64Encoder();
+ encoder.translate( inBuf, encodedBuf );
+ int nBytes = encodedBuf.length();
+ if ( nBytes > 0 ) {
+ s = new String(encodedBuf.toBytes(), 0, nBytes);
+ }
+ }
+ return s;
+ }
+
+ /**
+ * Test driver - just reads and parses an LDIF file, printing
+ * each record as interpreted
+ *
+ * @param args name of the LDIF file to parse
+ */
+ public static void main( String[] args ) {
+ if ( args.length != 1 ) {
+ System.out.println( "Usage: java LDIF <FILENAME>" );
+ System.exit( 1 );
+ }
+ LDIF ldif = null;
+ try {
+ ldif = new LDIF( args[0] );
+ } catch (Exception e) {
+ System.err.println("Failed to read LDIF file " + args[0] +
+ ", " + e.toString());
+ System.exit(1);
+ }
+ try {
+ for( LDIFRecord rec = ldif.nextRecord();
+ rec != null; rec = ldif.nextRecord() ) {
+ System.out.println( rec.toString() + '\n' );
+ }
+ } catch ( IOException ex ) {
+ System.out.println( ex );
+ System.exit( 1 );
+ }
+ System.exit( 0 );
+ }
+}
diff --git a/opends/tests/staf-tests/shared/java/ldapjdk/Reader.java b/opends/tests/staf-tests/shared/java/ldapjdk/Reader.java
new file mode 100644
index 0000000..a23a04b
--- /dev/null
+++ b/opends/tests/staf-tests/shared/java/ldapjdk/Reader.java
@@ -0,0 +1,277 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2010 Sun Microsystems, Inc.
+ */
+
+import netscape.ldap.*;
+import netscape.ldap.util.*;
+import java.util.*;
+import java.util.concurrent.BlockingQueue;
+import java.io.*;
+
+class Reader extends Thread {
+
+ BlockingQueue<Change> queue;
+ ArrayList<Server> masters;
+
+ public Reader(BlockingQueue<Change> q, ArrayList<Server> masters) {
+ this.queue = q;
+ this.masters = masters;
+ }
+
+ public void run() {
+ // master number in the array list
+ int masterN = 0;
+
+ // ECL "draft" mode index
+ int changeNumber = 0;
+
+ // ECL "opends" mode index
+ String eclCookie = EclReadAndPlay.INITIAL_COOKIE;
+
+
+ try {
+ Server master = null;
+ LDAPConnection masterConnection = new LDAPConnection();
+ LDAPSearchResults results = null;
+ LDAPEntry entry = null;
+ LDAPAttribute attr = null;
+ int idleTime = 0;
+
+ while (true) {
+ try {
+ master = masters.get(masterN);
+
+ // Connect to the Directory master
+ EclReadAndPlay.println("INFO", "Connecting to master " + master.host + ":" + master.port + " ......");
+ masterConnection.connect( master.host, master.port );
+ masterConnection.authenticate( 3, EclReadAndPlay.bindDn, EclReadAndPlay.bindPwd );
+ EclReadAndPlay.println("INFO", "...... Connected to master " + master.host + ":" + master.port );
+
+ // Set changenumber
+
+
+ // Try to retrieve the ECL index (changenumber|changelogcookie) of the last update read
+ // ---> use the CSN stored in the file under "db" directory
+ for ( CSN csn: EclReadAndPlay.RUV.values() ) {
+ String filter = "(& (objectclass=changelogentry)(replicationCSN="
+ + csn.getValue() + ") )";
+ results = masterConnection.search( "cn=changelog", LDAPv3.SCOPE_SUB, filter,
+ new String[] {"changeNumber", "changeLogCookie"} ,
+ false );
+ entry = results.next();
+
+ if ( EclReadAndPlay.eclMode.equals("draft") ) {
+ if ( entry != null ) {
+ attr = entry.getAttribute("changeNumber");
+ if (attr != null) {
+ String changeNumberString = attr.getStringValueArray()[0];
+ EclReadAndPlay.println("DEBUG", "Found changeNumber " + changeNumberString
+ + " for csn " + csn.getValue() );
+
+ int c = Integer.parseInt(changeNumberString);
+ if ( ( changeNumber == 0 ) || ( changeNumber > c ) ) {
+ EclReadAndPlay.println("DEBUG", "Setting changeNumber to " + ++c );
+ changeNumber = c;
+ }
+ } else {
+ EclReadAndPlay.println("WARNING", "Cannot find changenumber, setting it to 1");
+ changeNumber = EclReadAndPlay.INITIAL_CHANGENUMBER;
+ }
+ } else {
+ EclReadAndPlay.println("WARNING", "Cannot find a changelog entry for csn " + csn );
+ EclReadAndPlay.println("WARNING", "Will start from the first changelog entry");
+
+ results = masterConnection.search( "", LDAPv3.SCOPE_BASE, "(objectclass=*)",
+ new String[]{"firstChangeNumber"} , false );
+ entry = results.next();
+ attr = entry.getAttribute("firstChangeNumber");
+ if ( attr != null ) {
+ String changeNumberString = attr.getStringValueArray()[0];
+ EclReadAndPlay.println("DEBUG", "Found firstChangeNumber " + changeNumberString);
+
+ int c = Integer.parseInt(changeNumberString);
+ if ( ( changeNumber == 0 ) || ( changeNumber > c ) ) {
+ EclReadAndPlay.println("DEBUG", "Setting changeNumber to " + c );
+ changeNumber = c;
+ }
+ } else {
+ EclReadAndPlay.println("WARNING", "Cannot find firstChangeNumber, setting it to 1");
+ changeNumber = EclReadAndPlay.INITIAL_CHANGENUMBER;
+ }
+ }
+ } else if ( EclReadAndPlay.eclMode.equals("opends") ) {
+ if ( entry != null ) {
+ attr = entry.getAttribute("changeLogCookie");
+ if ( attr!= null ) {
+ eclCookie = attr.getStringValueArray()[0];
+ EclReadAndPlay.println("DEBUG", "Found changeLogCookie " + eclCookie
+ + " for csn " + csn.getValue() );
+ } else {
+ EclReadAndPlay.println("WARNING", "Cannot find a changelog entry for csn " + csn );
+ EclReadAndPlay.println("WARNING", "Will start from the first changelog entry");
+ eclCookie = EclReadAndPlay.INITIAL_COOKIE;
+ }
+ } else {
+ EclReadAndPlay.println("WARNING", "Cannot find a changelog entry for csn " + csn );
+ EclReadAndPlay.println("WARNING", "Will start from the first changelog entry");
+ eclCookie = EclReadAndPlay.INITIAL_COOKIE;
+ }
+ }
+ } /* for (CSN csn: ...) */
+
+ synchronized (EclReadAndPlay.lock) {
+ EclReadAndPlay.lock.notifyAll();
+ }
+
+ String[] attributes = new String[] {"replicationCSN", "replicaIdentifier", "targetDN",
+ "targetEntryUUID", "changeType", "changes",
+ "deleteOldRDN", "newRDN", "newSuperior",
+ "changeNumber", "changeHasReplFixupOp",
+ "changeLogCookie"};
+
+ while (idleTime < EclReadAndPlay.MAX_IDLE_TIME) {
+ if ( EclReadAndPlay.eclMode.equals("draft") ) {
+ int limit = changeNumber + (EclReadAndPlay.queueSize - 1);
+
+ String filter = "(& (changeNumber>=" + changeNumber + ")(changeNumber<="
+ + limit + ") )";
+
+ EclReadAndPlay.println("DEBUG", "Getting changes " + changeNumber + " to " + limit);
+ results = masterConnection.search("cn=changelog", LDAPv3.SCOPE_SUB, filter,
+ attributes , false );
+
+ } else if ( EclReadAndPlay.eclMode.equals("opends") ) {
+ // --control "1.3.6.1.4.1.26027.1.5.4:false:;"
+ String filter = "changetype=*";
+ LDAPSearchConstraints controls = new LDAPSearchConstraints();
+ LDAPControl eclControl = new LDAPControl("1.3.6.1.4.1.26027.1.5.4", false,
+ eclCookie.getBytes());
+ controls.setMaxResults(199);
+ controls.setServerControls(eclControl);
+
+ EclReadAndPlay.println("DEBUG", "Getting changes from cookie: " + eclCookie);
+ results = masterConnection.search("cn=changelog", LDAPv3.SCOPE_SUB, filter,
+ attributes , false, controls );
+ }
+
+
+ if ( ! results.hasMoreElements() ) {
+ // No new change found in retrocl => sleep 100 ms.
+ sleep(100);
+ idleTime += 100;
+ EclReadAndPlay.println("DEBUG", "No new change found in ECL => have slept for 100ms");
+ } else {
+ idleTime = 0;
+
+ // Forward all the results found to the application
+ while ( results.hasMoreElements() ) {
+ EclReadAndPlay.println("DEBUG", "Going through change entries found in the ECL.");
+ try {
+ entry = results.next();
+ } catch (LDAPException ldapEx) {
+ if ( ldapEx.getLDAPResultCode() == LDAPException.SIZE_LIMIT_EXCEEDED )
+ continue;
+ else
+ throw ldapEx;
+ }
+ //EclReadAndPlay.println("DEBUG", "Changelog entry: " + entry.toString());
+ try {
+ // Write the change in the queue
+ Change change = new Change(entry);
+ queue.put(change);
+ } catch (Exception e) {
+ EclReadAndPlay.println("DEBUG", "Ignoring change " + entry.getDN() );
+ if ( EclReadAndPlay.eclMode.equals("draft") )
+ EclReadAndPlay.inc_ignored(changeNumber);
+ else if ( EclReadAndPlay.eclMode.equals("opends") )
+ EclReadAndPlay.inc_ignored(eclCookie);
+ }
+
+ if ( EclReadAndPlay.eclMode.equals("draft") ) {
+ changeNumber++;
+ EclReadAndPlay.println("DEBUG", "change=" + entry.getDN() + ", changenumber = "
+ + changeNumber + ", count =" + results.getCount());
+ } else if ( EclReadAndPlay.eclMode.equals("opends") ) {
+ attr = entry.getAttribute("changeLogCookie");
+ if ( attr != null ) {
+ eclCookie = attr.getStringValueArray()[0];
+ EclReadAndPlay.println ("DEBUG", " ECL cookie value ========> " + eclCookie );
+ }
+ }
+ } /* while (result.hasMoreElements()) */
+
+ }
+
+ if ( EclReadAndPlay.displayMissingChanges == true ) {
+ if ( EclReadAndPlay.eclMode.equals("draft") ) {
+ results = masterConnection.search( "", LDAPv3.SCOPE_BASE, "(objectclass=*)",
+ new String[]{"lastChangeNumber"} , false );
+ entry = results.next();
+ attr = entry.getAttribute("lastChangeNumber");
+ if ( attr != null ) {
+ EclReadAndPlay.lastChangeNumber = Integer.parseInt(attr.getStringValueArray()[0]);
+ }
+ } else if ( EclReadAndPlay.eclMode.equals("opends") ) {
+ results = masterConnection.search( "", LDAPv3.SCOPE_BASE, "(objectclass=*)",
+ new String[]{"lastExternalChangelogCookie"} , false );
+ entry = results.next();
+ attr = entry.getAttribute("lastExternalChangelogCookie");
+ if ( attr != null ) {
+ EclReadAndPlay.lastExternalChangelogCookie = attr.getStringValueArray()[0];
+ }
+ }
+ }
+
+ } /* while (idleTime <= EclReadAndPlay.MAX_IDLE_TIME) */
+
+ EclReadAndPlay.println("WARNING", "No new changes read in the ECL for " + Integer.toString(idleTime) +
+ " milliseconds. ======> EXIT");
+ System.exit(0);
+ } catch( LDAPException e ) {
+
+ int errorCode = e.getLDAPResultCode();
+
+ // if server is down => switch
+ if ( ( errorCode == 91 ) || ( errorCode == 81 ) || ( errorCode == 80 ) ) {
+ // clear the queue of changes
+ queue.clear();
+ EclReadAndPlay.println( "WARNING", "Connection lost to " + master.host + ":" + master.port + ".");
+ masterN = (masterN+1) % masters.size();
+ } else {
+ EclReadAndPlay.println( "ERROR" , e.toString() );
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+ } /* while (true) */
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+}
diff --git a/opends/tests/staf-tests/shared/java/ldapjdk/Server.java b/opends/tests/staf-tests/shared/java/ldapjdk/Server.java
new file mode 100644
index 0000000..fc34c3c
--- /dev/null
+++ b/opends/tests/staf-tests/shared/java/ldapjdk/Server.java
@@ -0,0 +1,48 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2010 Sun Microsystems, Inc.
+ */
+
+import java.util.*;
+
+public class Server {
+ public String host;
+ public int port;
+
+ public Server (String host, int port) {
+ this.host=host;
+ this.port=port;
+ }
+
+ public Server (String hostPort) {
+ StringTokenizer st = new StringTokenizer(hostPort, ":");
+ this.host=st.nextToken();
+ this.port=Integer.parseInt(st.nextToken());
+ }
+
+ public String toString() {
+ return (host + ":" + port);
+ }
+}
diff --git a/opends/tests/staf-tests/shared/java/ldapjdk/Writer.java b/opends/tests/staf-tests/shared/java/ldapjdk/Writer.java
new file mode 100644
index 0000000..b322819
--- /dev/null
+++ b/opends/tests/staf-tests/shared/java/ldapjdk/Writer.java
@@ -0,0 +1,122 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2010 Sun Microsystems, Inc.
+ */
+
+import netscape.ldap.*;
+import netscape.ldap.util.*;
+import java.util.*;
+import java.util.concurrent.BlockingQueue;
+import java.io.*;
+
+class Writer extends Thread {
+
+ BlockingQueue<Change> q;
+ String hostport;
+
+ public Writer(BlockingQueue<Change> q, String hostport) {
+ this.q = q;
+ this.hostport = hostport;
+ }
+
+ public void run() {
+ try {
+ Server application = new Server( hostport );
+ ImprovedLDAPConnection applicationConnection = new ImprovedLDAPConnection();
+
+ // Connect to the stand-alone server
+ EclReadAndPlay.println("INFO", "****** Connecting to application "
+ + application.host + ":" + application.port + " ......");
+ applicationConnection.connect( application.host, application.port );
+ applicationConnection.authenticate( 3, EclReadAndPlay.bindDn, EclReadAndPlay.bindPwd );
+ EclReadAndPlay.println("INFO", "****** ...... Connected to application "
+ + application.host + ":" + application.port );
+
+ while (true) {
+ // Read change from the queue
+ Change change = q.take();
+ //EclReadAndPlay.println ("DEBUG", "Change read from the queue -----> : " + change.toString() );
+
+ CSN RUVcsn=EclReadAndPlay.RUV.get(change.replicaIdentifier);
+ if ( RUVcsn != null ) {
+ // if operation is not replicated
+ if ( change.csn == null )
+ continue;
+
+ if (change.csn.compareTo(RUVcsn) < 0) {
+ // EclReadAndPlay.println ("DEBUG", Integer.toHexString(i.intValue()) + " < " + Integer.toHexString(l.intValue()) );
+ EclReadAndPlay.println("DEBUG", "Operation " + change.changeNumberValue + " csn "
+ + change.csn + " has already been replayed");
+ continue;
+ }
+ }
+
+ try {
+ // Write change on stand-alone server
+ applicationConnection.apply(change);
+
+ // Write change CSN to file under "db" directory
+ File f;
+ if (EclReadAndPlay.files.containsKey(change.replicaIdentifier)) {
+ f = EclReadAndPlay.files.get(change.replicaIdentifier);
+ // f.renameTo(new File(EclReadAndPlay.dbPath, new String(change.replicaIdentifier+".tmp") ));
+ } else {
+ f = new File(EclReadAndPlay.dbPath, change.replicaIdentifier + ".csn");
+ EclReadAndPlay.files.put(change.replicaIdentifier,f);
+ }
+
+ FileWriter out = new FileWriter(f);
+ out.write(change.csn.value);
+ out.flush();
+ out.close();
+
+ EclReadAndPlay.RUV.put(change.replicaIdentifier,change.csn);
+
+ if ( EclReadAndPlay.eclMode.equals("draft") )
+ EclReadAndPlay.inc_ops(change.changeNumber);
+ else if ( EclReadAndPlay.eclMode.equals("opends") )
+ EclReadAndPlay.inc_ops(change.changelogCookie);
+
+ // Log a message for the written change on "logs/access" file
+ EclReadAndPlay.accessOut.println(EclReadAndPlay.getDate()
+ + "- INFO: " + change.type + " \""
+ + change.dn + "\" (" + change.csn +" / "
+ + change.changeNumber + ")" );
+ } catch (Exception e) {
+ EclReadAndPlay.println( "ERROR", e.toString() );
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ //nb_changes++;
+
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+}
--
Gitblit v1.10.0