| opends/tests/staf-tests/shared/java/ldapjdk/CSN.java | ●●●●● patch | view | raw | blame | history | |
| opends/tests/staf-tests/shared/java/ldapjdk/Change.java | ●●●●● patch | view | raw | blame | history | |
| opends/tests/staf-tests/shared/java/ldapjdk/EclReadAndPlay.java | ●●●●● patch | view | raw | blame | history | |
| opends/tests/staf-tests/shared/java/ldapjdk/ImprovedLDAPConnection.java | ●●●●● patch | view | raw | blame | history | |
| opends/tests/staf-tests/shared/java/ldapjdk/LDIF.java | ●●●●● patch | view | raw | blame | history | |
| opends/tests/staf-tests/shared/java/ldapjdk/Reader.java | ●●●●● patch | view | raw | blame | history | |
| opends/tests/staf-tests/shared/java/ldapjdk/Server.java | ●●●●● patch | view | raw | blame | history | |
| opends/tests/staf-tests/shared/java/ldapjdk/Writer.java | ●●●●● patch | view | raw | blame | history |
opends/tests/staf-tests/shared/java/ldapjdk/CSN.java
New file @@ -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); } } opends/tests/staf-tests/shared/java/ldapjdk/Change.java
New file @@ -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 +")"); } } opends/tests/staf-tests/shared/java/ldapjdk/EclReadAndPlay.java
New file @@ -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() ); } } } opends/tests/staf-tests/shared/java/ldapjdk/ImprovedLDAPConnection.java
New file @@ -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 + ")" ); } } } opends/tests/staf-tests/shared/java/ldapjdk/LDIF.java
New file @@ -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 ); } } opends/tests/staf-tests/shared/java/ldapjdk/Reader.java
New file @@ -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); } } } opends/tests/staf-tests/shared/java/ldapjdk/Server.java
New file @@ -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); } } opends/tests/staf-tests/shared/java/ldapjdk/Writer.java
New file @@ -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); } } }