java读取ldif文件并创建新的节点
所需jar包ldap.jar、 jldap-4.3-source.jar
http://www.java2s.com/Code/Jar/l/Downloadldapjar.htm
浏览器输入http://maven.aliyun.com/nexus进入后搜索jldap,找到com.novell.ldap 这里我用的是4.3版本,点击source下载
https://www.novell.com/documentation/developer/samplecode/jldap_sample/
打开浏览器输入以上地址,Ldif2Ldap.java并找到LDIFReader.java.这个类就是用来读取ldif文件并添加到ldap目录服务中,再将ldap.jar放入项目中。
- 方法一:
使用Ldif2Ldap.java,传入相应的参数(<文件名称> <IP> <登录名> <密码>)就可以将ldif文件导入到ldap目录服务中。但这里需要注意ldif文件的格式,否则回报com.novell.ldap.ldif_dsml.LDIFReader: version: found 。。。
因为这里采用的是Novell 导入需要LDIF 1格式的文件,以下是LDIF 1文件的基本规则:
- 第一个非注释行必须是版本号:1.
- 版本号后面跟有一个或多个记录。
- 每个记录由多个字段组成,一行一个字段。
- 各行使用换行符或回车符/换行符对分隔。
- 各记录由一个或多个空行分隔。
- 存在两种不同类型的 LDIF 记录:内容记录和更改记录。对 LDIF 文件可以包含的记录数目没有限制,但它们必须属于同一类型。在同一个 LDIF 文件中不能既有内容记录又有更改记录。
- 以井字符 (#) 开头的行是注释行,在处理 LDIF 文件时将被忽略。
version:1 dn:: Yz3kuK3ljY7kurrmsJHlhbHlkozlm70= changetype:add objectClass: top objectClass: country c:: 5Lit5Y2O5Lq65rCR5YWx5ZKM5Zu9 dn:: bz3lm5vlt50sIGM95Lit5Y2O5Lq65rCR5YWx5ZKM5Zu9 changetype:add objectClass: top objectClass: organization o:: 5Zub5bed dn:: bz3miJDpg70sbz3lm5vlt50sIGM95Lit5Y2O5Lq65rCR5YWx5ZKM5Zu9 changetype:add objectClass: top objectClass: organization o:: 5oiQ6YO9
- 注:dn:安全 UTF-8 相对判别名 dn::Base64 编码的相对判别名
运行后,打开浏览器输入以下地址
https://www.netiq.com/communities/cool-solutions/cool_tools/gawors-excellent-ldap-browsereditor-v282/
下载LDAP Browser\Editor v2.8.2后双击lbe.jar,连接ldap后,就可以发现数据已成功的添加进去了
- 方法二:
使用Ldif2Ldap.java,传入相应的参数(<文件名称> <IP> <登录名> <密码>)就可以将ldif文件导入到ldap目录服务中。
int version = 1; int ldapPort = LDAPConnection.DEFAULT_PORT; int ldapVersion = LDAPConnection.LDAP_V3; String fileName = args[0]; String ldapHost = args[1]; String loginDN = args[2]; String password = args[3]; LDIFReader reader = null; LDAPEntry entry; LDAPMessage msg, retMsg; LdifImport readerTest = new LdifImport(); LDAPConnection lc = new LDAPConnection(); File file = new File(fileName); if(!file.exists()){ logger.error("要读取的文件不存在"); return false; } try { FileInputStream fis = new FileInputStream(new File(fileName)); reader = new LDIFReader(fis, version); } catch (Exception e) { logger.error("读取 " + fileName +"文件失败"); return false; }
这里LDIFReader类在方法一中调用的是ldap.jar中的类,考虑到ldif文件的格式,我在这里打算更改LDIFReader类中的源代码,在 jldap-4.3-source.jar 的工具包中,复制并修改。
更改后的LDIFReader.java
package com.cn.ccc.ggg.ldap.core.common; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import com.novell.ldap.LDAPAttribute; import com.novell.ldap.LDAPAttributeSet; import com.novell.ldap.LDAPControl; import com.novell.ldap.LDAPEntry; import com.novell.ldap.LDAPException; import com.novell.ldap.LDAPLocalException; import com.novell.ldap.LDAPMessage; import com.novell.ldap.LDAPModification; import com.novell.ldap.LDAPSearchResult; import com.novell.ldap.LDAPAddRequest; import com.novell.ldap.LDAPDeleteRequest; import com.novell.ldap.LDAPModifyDNRequest; import com.novell.ldap.LDAPModifyRequest; import com.novell.ldap.util.Base64; import com.novell.ldap.util.LDAPReader; /** * 处理inputStream对象以读取LDIF文件的类 * * <p>该calss从LDIF文件读取LDAP条目和LDAP请求</p> * * <p>构造函数使用默认大小值8,192来创建 缓冲字符输入流并假定大小很大足以容纳下一个字段的dn字段和第一行当前正在阅读的LDIF文件中的第一条记录</p> * * <p>构造函数使用'1'作为默认的LDIF文件版本</p> */ public class LDIFReader implements LDAPReader { private boolean requestFile=true; // request file=true private String version; // LDIF file version private int reqType; // int rep. of name private int lNumber; // line number private int dnlNumber; // dn line number private int fNumber = 0; // number of fields private byte[] bytes= new byte[0]; // for any byte value private boolean control = false; // is control field private String entryDN; // entry dn private String[] modInfo; // for moddn private ArrayList rFields = new ArrayList(); // record fields private ArrayList cList = new ArrayList(); // control list private BufferedReader bufReader; private LDAPControl[] controls = null; // req controls private LDAPEntry currentEntry = null; private LDAPModification[] mods; private LDAPMessage currentRequest = null; /** * 通过初始化LDIF_VERSION,isRequest构造LDIFReader对象, * InputStreamReader和BufferedReader * * @param in The InputStream object to be processed by LDIFReader */ public LDIFReader( InputStream in ) throws IOException, LDAPLocalException { this( in, 1, 8192 ); return; } /** * 通过初始化LDIF_VERSION,isRequest构造LDIFReader对象, * InputStreamReader和BufferedReader * * @param in The Inputstream object to be processed by LDIFReader * @param version The version currently used in the LDIF file */ public LDIFReader( InputStream in, int version ) throws IOException, LDAPLocalException { this( in, version, 8192 ); return; } /** * 通过初始化LDIF_VERSION,isRequest构造LDIFReader对象, * InputStreamReader和BufferedReader * * @param in The Inputstream object to be processed by LDIFReader * @param version The version currently used in the LDIF file * @param bufSize The size used to create a buffering character-input * stream. The defaule value is 8,192. */ public LDIFReader(InputStream in, int version, int bufSize) throws IOException, LDAPLocalException { super(); String line = null; if ( version != 1 ) { // check LDIF file version throw new RuntimeException("com.novell.ldap.ldif_dsml.LDIFReader:" + "found: " + version + ", Should be: 1"); } setVersion( version ); InputStreamReader isr = new InputStreamReader(in, "US-ASCII"); bufReader = new BufferedReader(isr); //为了确定它是否是LDIF内容文件或LDIF更改 //文件,dn字段的第一行和旁边的有意义的行 // dn字段被读入内存。 //在版本行之前跳过前面的空行和注释行 /* while( (line = bufReader.readLine())!= null && (line.length() == 0 || line.startsWith("#")) ) { this.lNumber++; } //已经到达文件的末尾 if ( line == null ) { throw new LDAPLocalException( "com.novell.ldap.ldif_dsml.LDIFReader:" + " The file contains no LDIF info", LDAPException.LOCAL_ERROR); } //需要增加行号 this.lNumber++; // 1 //第一个有效行(版本行)。 检查版本行 if (line.startsWith("version:")) { this.version = line.substring("version:".length()).trim(); if ( !this.version.equals( "1") ) { throw new LDAPLocalException( "com.novell.ldap.ldif_dsml.LDIFReader: " + "version: found '" + version + "' (on line " + this.lNumber + " of the file), should be '1'", LDAPException.LOCAL_ERROR); } }else { // 第一行有效行不是版本行 throw new LDAPLocalException("com.novell.ldap.ldif_dsml.LDIFReader:" + " Version line must be the first meaningful line(on line " + this.lNumber + " of the file)", LDAPException.LOCAL_ERROR); } */ // 跳过版本行和之间的空行和注释行 // LDIF的第一个记录中的dn字段的第一行 // 文件,读取第一条记录的dn字段的第一行 do { //标记第一个dn行,所以我们以后可以回到这里 bufReader.mark( bufSize ); line=bufReader.readLine(); if ( line == null) { // end of file throw new LDAPLocalException( "com.novell.ldap.ldif_dsml." + "LDIFReader: the LDIF file only contains version line.", LDAPException.LOCAL_ERROR); } this.lNumber++; } while((line.length()== 0) || line.startsWith("#")); //稍后会检查dn字段; 现在忽略了其余的一行 // dn字段,并在dn字段后面读取有效行 while ( (line = bufReader.readLine()) != null ) { // ! a part of dn field ! a comment line if ( !line.startsWith(" ") && !line.startsWith("#") ) { //到第一个记录的结尾 if ( line.length() == 0 ) { //空行 这个记录只有dn字段 throw new LDAPLocalException("com.novell.ldap.ldif_dsml." + "LDIFReader: the first record only has dn field(line " + this.lNumber + " of the file)", LDAPException.LOCAL_ERROR); } //刚刚读取的行应该是开头的行 //'control', 'changetype', 属性名 break; } } if ( line == null) { // end of file throw new LDAPLocalException("com.novell.ldap.ldif_dsml." + "LDIFReader: the first record only has dn field(line " + this.lNumber + " of the file)", LDAPException.LOCAL_ERROR); } if(line.startsWith("changetype")||line.startsWith("control")){ setRequest(true); // LDIF使用LDAP操作请求更改文件 } else { setRequest(false); // 带有LDAP条目的LDIF内容文件 } setRequest(true); //返回到LDIF文件的第一个记录的开头 //稍后读取可以从第一条记录开始 bufReader.reset(); // this.lNumber--; return; } /** * 获取与输入流相关联的LDIF数据的版本 * * @return the version number */ public String getVersion() { return version; } /** * 获取与输入流相关联的LDIF数据的版本 * * @param value the version number */ private void setVersion(int value) { version = String.valueOf(value); return; } /** * 如果请求数据与输入流相关联,则返回true, * 或如果内容数据为false。 * * @return true if input stream contains request data. */ public boolean isRequest() { return requestFile; } /** * 设置正在读取的文件的请求类型,如果请求数据为true * 或如果内容数据为false。 * * @param type sets the type of file to content or request data. */ private void setRequest( boolean type) { requestFile = type; return; } /** * 从LDIF请求(更改)文件或内容文件读取LDAP请求。. * * @return LDAPMessage specified by the record */ public LDAPMessage readMessage() throws IOException, LDAPException { readRecordFields(); // 读取记录字段 if ( this.rFields == null ) { // 文件结尾 return null; } toRecordProperties(); // 设置记录属性 if (!isRequest()) { return new LDAPSearchResult(currentEntry, null); } switch( this.reqType ) { case LDAPMessage.SEARCH_RESPONSE : this.currentRequest = new LDAPAddRequest(currentEntry, controls); break; case LDAPMessage.ADD_REQUEST : this.currentRequest = new LDAPAddRequest(currentEntry, controls); break; case LDAPMessage.DEL_REQUEST : this.currentRequest = new LDAPDeleteRequest(this.entryDN, controls); break; case LDAPMessage.MODIFY_RDN_REQUEST : boolean delOldRdn; if ( Integer.parseInt(this.modInfo[1]) == 1 ) { delOldRdn = true; } else { delOldRdn = false; } if((modInfo[2].length())==0 ) { this.currentRequest = new LDAPModifyDNRequest( this.entryDN, this.modInfo[0], null, delOldRdn, controls); } else { this.currentRequest = new LDAPModifyDNRequest(this.entryDN, this.modInfo[0], modInfo[2], delOldRdn, controls); } break; case LDAPMessage.MODIFY_REQUEST : this.currentRequest = new LDAPModifyRequest(this.entryDN, mods, controls); break; default: } return this.currentRequest; } /** * 读取当前记录中的所有行,将记录行转换为 * 记录字段,并修剪记录字段中的多余空格。 */ private void readRecordFields() throws IOException, LDAPException { String line; StringBuffer bLine = new StringBuffer(80); // clean rFields this.rFields.clear(); //跳过空和注释行并读取第一个dn //行记录 while( (line = bufReader.readLine())!= null && (line.length() == 0 || line.startsWith("#")) ) { this.lNumber++; } this.lNumber++; this.dnlNumber = this.lNumber; if (line == null) { // 文件结尾 this.rFields = null; } else { //检查dn行是否以'dn:'开头 if (!line.startsWith("dn:")) { throw new LDAPLocalException("com.novell.ldap.ldif_dsml." + "LDIFReacer: Any record should start with 'dn:'(on line " + this.lNumber + " of the file).", LDAPException.LOCAL_ERROR); } //保存第一个dn行 bLine.append(line); //读取除注释行之外的记录的其他行。 //读取停止在用于分隔的空行 //当前记录与下一个 while ((line = bufReader.readLine())!=null && line.length()!=0 ) { if ( !line.startsWith("#") ) { //跳过注释行 if ( line.startsWith(" ") ) { //续行? // trim off leading ' ' and append it to previous line bLine.append(line.substring(1, line.length())); } else { // 新的一行 // handle pewvious field bLine = trimField(bLine); // trime上一个字段 if(!this.control) { // 如果不是,保存它 this.rFields.add(bLine); // 一个控制字段 } //处理新行 bLine = new StringBuffer(80);// create a new buffer bLine.append(line); // to hold new line } } this.lNumber++; } //修剪并保存最后一个字段 bLine = trimField(bLine); this.rFields.add(bLine); this.lNumber++; // 增加行号 this.fNumber = this.rFields.size(); // 获取字段数 } return; } /** * 设置记录属性。 * <p>对于LDIF内容记录,创建由此记录指定的LDAPEntry</p> * * <p>对于LDIF更改记录,根据请求类型,将创建LDAPEntry,modInfo或LDAPModifiction数组以及与请求相关联的控件</p> */ private void toRecordProperties() throws IOException, LDAPException { int index; String req; // set entry DN StringBuffer dnField = (StringBuffer)this.rFields.get(0); if (dnField.charAt(3) != ':') { // commom string value this.entryDN = dnField.substring( 3, dnField.length()); } else { // base64 encoded this.bytes = Base64.decode(dnField, 4, dnField.length()); try { this.entryDN = new String(this.bytes, "UTF-8"); } catch( UnsupportedEncodingException ue) { throw new RuntimeException( "UTF-8 String encoding not supported by JVM"); } } if ( !isRequest() ) { // 是一个内容LDIF文件 toLDAPEntry(); } else { // 是一个更改LDIF文件 index = 10; // length of 'changetype' // ctField - changetype field StringBuffer ctField = (StringBuffer)this.rFields.get(1); this.reqType = LDAPMessage.ADD_REQUEST; toLDAPEntry(); /*if(!ctField.substring(0, index).equalsIgnoreCase("changetype")) { throw new LDAPLocalException("com.novell.ldap.ldif_dsml." +"LDIFReader: malformed changetype field in record starting" + " on line " + this.dnlNumber + " of the file).", LDAPException.LOCAL_ERROR); } // 获取类型: 'add', 'delete','moddn', 'modrdn', or 'modify' req = ctField.substring(index+1); // 设置请求类型 if ( req.equalsIgnoreCase("add") ) { this.reqType = LDAPMessage.ADD_REQUEST; toLDAPEntry(); } else if ( req.equalsIgnoreCase("delete") ) { this.reqType = LDAPMessage.DEL_REQUEST; } else if ( req.equalsIgnoreCase("modrdn") ) { this.reqType = LDAPMessage.MODIFY_RDN_REQUEST; toModInfo(); } else if ( req.equalsIgnoreCase("moddn") ) { this.reqType = LDAPMessage.MODIFY_RDN_REQUEST; toModInfo(); } else if ( req.equalsIgnoreCase("modify") ) { this.reqType = LDAPMessage.MODIFY_REQUEST; toLDAPModifications(); } else { throw new LDAPLocalException("com.novell.ldap.ldif_dsml." + "LDIFReader: unsupported request type '" + req + "' specified in changetype filed of the record starting " + "on line " + this.dnlNumber + " of the file.", LDAPException.LOCAL_ERROR); }*/ if (this.cList.size() > 0) { this.controls = new LDAPControl[this.cList.size()]; } } return; } /** * 处理LDIF记录字段以生成LDAPEntry。 */ private void toLDAPEntry() throws LDAPLocalException { int i, index, fieldIndex; String attrName = null; StringBuffer currentField; LDAPAttributeSet attrSet = new LDAPAttributeSet(); if ( !isRequest() ) { // 跳过 dn 字段 fieldIndex = 1; } else { // 跳过dn,control和changetype字段 fieldIndex = 2; } for (i=fieldIndex; i<this.fNumber; i++) { currentField = (StringBuffer)this.rFields.get(i); // ':' 分离属性名称和属性值 index = IndexOf(currentField, ':'); if (index == -1) { // ':' not found throw new LDAPLocalException("com.novell.ldap.ldif_dsml." + "LDIFReader: missing ':' after attribute name in record " + "starting on line " + this.dnlNumber +" of the file.", LDAPException.LOCAL_ERROR); } // 获取属性名称 attrName = currentField.substring(0,index); // 如果属性名称不存在,则添加 if ( attrSet.getAttribute(attrName) == null ) { // add it to attrSet with no value attrSet.add(new LDAPAttribute(attrName)); } if(currentField.length() > index+1){ // 将属性值添加到属性中 if (currentField.charAt(index+1)==':') { // base64编码的属性值 attrSet.getAttribute(attrName).addBase64Value(currentField. substring(index+2)); } else if (currentField.charAt(index+1)=='<'){ // 文件URL属性值 attrSet.getAttribute(attrName).addBase64Value(currentField. substring(index+2)); } else { // 字符串值 String vals=currentField.substring(index+1).trim(); attrSet.getAttribute(attrName).addValue(vals); // attrSet.getAttribute(attrName).addValue(currentField. // substring(index+1)); } } else if(currentField.length() == index+1){ String vals=new String(""); attrSet.getAttribute(attrName).addValue(vals); } } // 构造currentEntry this.currentEntry = new LDAPEntry(this.entryDN, attrSet); return; } /** * 构建包含moddn信息的String数组对象。 */ private void toModInfo() throws LDAPLocalException { int index = 6; // length of "newrdn" int fieldIndex = 2; // reference newrdn field this.modInfo = new String[3]; StringBuffer currentField = (StringBuffer)this.rFields.get(fieldIndex); if( ! currentField.substring(0, index+1).equalsIgnoreCase("newrdn:")) { throw new LDAPLocalException("com.novell.ldap.ldif_dsml.LDIFReader:" + " malformed newrdn field in record starting on line " + this.dnlNumber + " of the file.", LDAPException.LOCAL_ERROR); } // get newrdn if ( currentField.charAt(index+1) != ':') { // common string value this.modInfo[0] = currentField.substring(index+1); } else { // decode newrdn this.bytes = Base64.decode( currentField, index+2, currentField.length()); try { this.modInfo[0] = new String(this.bytes, "UTF-8"); } catch( UnsupportedEncodingException ue) { throw new RuntimeException( "UTF-8 String encoding not supported by JVM"); } } fieldIndex++; // reference deleteOleRDN field index = 13; // length of "deleteoldrdn" currentField = (StringBuffer)this.rFields.get(fieldIndex); if( ! currentField.substring(0, index).equalsIgnoreCase( "deleteoldrdn:") ) { throw new LDAPLocalException("com.novell.ldap.ldif_dsml.LDIFReader:" + " malformed deleteoldrdn field in record starting on line " + this.dnlNumber + " of the file.", LDAPException.LOCAL_ERROR); } char c = currentField.charAt(index); if (c == '1') { this.modInfo[1] = new String("1"); } else if (c == '0'){ this.modInfo[1] = new String("0"); } else { throw new LDAPLocalException("com.novell.ldap.ldif_dsml.LDIFReader:" + " value for deleteoldrdn field should '0' or '1', found '" + c + "' in the record starting on line " + this.dnlNumber + " of the file.", LDAPException.LOCAL_ERROR); } fieldIndex++; // reference newsuperior field if (fieldIndex == this.fNumber) { // no newsuperior spefified this.modInfo[2] = new String(""); } else { // there is a newsuperior currentField = (StringBuffer)this.rFields.get(fieldIndex); index = 12; // length of "newsuperior:" if( ! currentField.substring(0, index).equalsIgnoreCase( "newsuperior:")) { throw new LDAPLocalException("com.novell.ldap.ldif_dsml." + "LDIFReader: malformed newsuperior field in the record " + "starting on line " + this.dnlNumber + " of the file.", LDAPException.LOCAL_ERROR); } if ( currentField.charAt(index) != ':') { // commom string value this.modInfo[2] = currentField.substring(index); } else { // base64 encoded value this.bytes = Base64.decode( currentField, index+1, currentField.length()); this.modInfo[2] = new String(this.bytes);; } } return; } /** * 基于LDIF修改记录的内容构建LDAPModification数组。 */ private void toLDAPModifications()throws LDAPLocalException{ int i, index; int fieldIndex = 2; // 跳过 dn, control, and changetype 字段 String attrName, opName; LDAPAttribute attr = null; ArrayList modList = new ArrayList(); if (!(this.rFields.get(this.fNumber-1)).toString(). equalsIgnoreCase("-") ) { throw new LDAPLocalException("com.novell.ldap.ldif_dsml." + "LDIFReader: modify record not ends with '-' in the record" + " starting on line " + this.dnlNumber + " of the file.", LDAPException.LOCAL_ERROR); } // 填充LDAPModification数组对象 for (i=fieldIndex; i<this.fNumber; i++) { // 找到":"分开mod操作和attr名称 index = IndexOf((StringBuffer)this.rFields.get(i), ':'); if (index == -1) { // ':' not found throw new LDAPLocalException("com.novell.ldap.ldif_dsml." + "LDIFReader: malformed opName:attrName field in the record" + " starting on line " + this.dnlNumber + " of the file.", LDAPException.LOCAL_ERROR); } StringBuffer nextField = (StringBuffer)this.rFields.get(i); opName= nextField.substring(0, index); attrName= nextField.substring(index+1); i++; // 指向attrName:attrValue字段 nextField = (StringBuffer)this.rFields.get(i); // 构建每个LDAPModification对象并将其添加到modList if (nextField.charAt(0)!='-') { // 至少有一个 属性名称:属性值 字段 for ( ; nextField.charAt(0)!='-'; i++, nextField = (StringBuffer)this.rFields.get(i)) { // 下标分离属性名称和属性值 if ((index=IndexOf(nextField, ':')) == -1) { throw new LDAPLocalException("com.novell.ldap." + "ldif_dsml.LDIFReader : no ':' found in attrName:" + "attrValue field in the record starting on line " + this.dnlNumber + " of the file.", LDAPException.LOCAL_ERROR); } else { // 比较opName:attrName和 attrName:attrValue字段 String aName = nextField.substring(0, index); if (!aName.equalsIgnoreCase(attrName)) { throw new LDAPLocalException("com.novell.ldap." + "ldif_dsml.LDIFReader : found attribute name '" + aName + "', should be '" + attrName + "' in attrName:attrValue field in the record " + "starting on line " + this.dnlNumber + " of the file.", LDAPException.LOCAL_ERROR); } // create attr and add value to it attr = new LDAPAttribute(attrName); if (nextField.charAt(index+1)==':') { // base64 encoded attribute value attr.addBase64Value(nextField.substring(index+2)); } else if (nextField.charAt(index+1)=='<'){ // file URL attribute value attr.addBase64Value(nextField.substring(index+2)); } else { // string value attr.addValue(nextField.substring(index+1)); } if ( opName.equalsIgnoreCase("add") ) { modList.add( new LDAPModification( LDAPModification.ADD, attr)); } else if ( opName.equalsIgnoreCase("delete") ) { modList.add( new LDAPModification( LDAPModification.DELETE, attr)); } else if ( opName.equalsIgnoreCase("replace") ) { modList.add( new LDAPModification( LDAPModification.REPLACE, attr)); } else { throw new LDAPLocalException("com.novell.ldap." + "ldif_dsml.LDIFReader : Not supported modify " + " request (" + opName + ") specified in " + "record starting on line " + this.dnlNumber + " of the file.", LDAPException.LOCAL_ERROR); } } } } else { // there is no attribute value specified; this could be // true for 'delete' and 'replace' modify operation attr = new LDAPAttribute(attrName); if ( opName.equalsIgnoreCase("delete") ) { modList.add( new LDAPModification( LDAPModification.DELETE, attr)); } else if ( opName.equalsIgnoreCase("replace") ) { modList.add( new LDAPModification( LDAPModification.REPLACE, attr)); } else { throw new LDAPLocalException("com.novell.ldap.ldif_dsml." + "LDIFReader: For '" + opName + "', no value " + "specified for atribute '" + attrName + "' in the record starting on line " + this.dnlNumber + " of the file.", LDAPException.LOCAL_ERROR); } } } this.mods = new LDAPModification[modList.size()]; this.mods = (LDAPModification[])modList.toArray(this.mods); return; } /** * 返回指定字符首次出现的StringBuffer对象内的索引。 * * @param bl The StringBuffer object * @param ch The character to look for in the StringBuffer object * * @return The index of the first occurence of the character in the * StringBuffer object, or -1 if the character does not occur. */ private int IndexOf(StringBuffer bl, int ch) { if (bl != null ) { for (int i=0;i<bl.length(); i++) { if(bl.charAt(i) == ch) { return i; } } } return -1; } /** * <tt>去空字段<tt> 修剪一个字段中的多余空格。 */ private StringBuffer trimField( StringBuffer line) throws LDAPLocalException { int c, lastChar = 0, charIndex = 0; char t; char[] newChars; boolean isEncoded=false, isURL=false, criticality = false; String oid = null; if ((line == null)||((c=IndexOf(line,':'))==-1)) { // not all fields contain ':' return line; } // elminate any trailing spaces lastChar = line.length() - 1; while( line.charAt(lastChar) == ' ') { lastChar--; } // create newChars newChars = new char[lastChar+1]; if( (c > 6) && (line.substring(0,c).equals("control"))) { // this is a control field this.control = true; c++; // skip past ':' // eliminate any spaces after ':' while( (c <= lastChar) && (line.charAt(c) == ' ')) { c++; } } else { // not a control field. it's 'dn', //'changetype', or 'attrName' field this.control = false; // copy field name and ':', eg. 'dn:', 'changetype:', or 'attrName:' line.getChars(0, c+1, newChars, 0); // skip over copied chars charIndex += c + 1; // c points to char right after first ':' c++; } if(!this.control) { // // not a control field. check if '::' or ':<' if( c <= lastChar) { t = line.charAt(c); if( t == ':') { newChars[charIndex++] = ':'; // save the ':' to c++; // point to value } else if( t == '<') { newChars[charIndex++] = '<'; // save the '<' to c++; // point to value } } // for case like attr: <value> boolean nonfile=false; String fredir= line.substring(c); if(fredir.length()>0 && fredir.charAt(0) != '<'){ String cstr=fredir.trim(); if(cstr.length()>0 && cstr.charAt(0) == '<'){ nonfile=true; } } // eliminate any space(s) after ':' or '<' while( (c <= lastChar) && (line.charAt(c) == ' ')) { c++; } // for case like attr: <value> if(nonfile==true){ c--; } if( c <= lastChar) { // thers is a value specified // copy field value line.getChars(c, lastChar+1, newChars, charIndex); charIndex += lastChar - c + 1; // create a new StringBuffer object with capacity of lastChar StringBuffer newBuf = new StringBuffer(lastChar); // copy the filed represented by newChars newBuf.append( newChars, 0, charIndex); // return the trimed field return newBuf; } else if ( line.length() == c){ StringBuffer newBuf= new StringBuffer(); line.getChars(c, lastChar+1, newChars, charIndex); charIndex += lastChar - c + 1; newBuf.append( newChars, 0, charIndex); return newBuf; } else { // there is no value specified throw new LDAPLocalException("com.novell.ldap.ldif_dsml." + "LDIFReader: a field contains no value after ':'. the " + "field is in the record starting on line " + this.dnlNumber + " of the file.", LDAPException.LOCAL_ERROR); } } else { // a control field // process values for control. a control field may looks like // 1. control: 1.2.3.4 true: control value // 2. control: 1.2.3.4: control value // 3. control: 1.2.3.4 // extra spaces are possible between oid, criticality, and value. // oid is a must, while criticalitty and value can be absent. // get control oid int b = c; while(c <= lastChar) { // an oid consists of dots and digits t = line.charAt(c); if( (t == '.') || (Character.isDigit(t))) { c++; continue; } break; } if( b == c) { // control with no oid throw new LDAPLocalException("com.novell.ldap.ldif_dsml." + "LDIFReader: Control with no oid in the record " + "starting on line " + this.dnlNumber + " of the file.", LDAPException.LOCAL_ERROR); } else { // control has iod, get local copy of oid char[] chars = new char[c-b]; line.getChars(b, c, chars, 0); oid = new String(chars); } if ( c > lastChar) { // control only has an oid. create LDAPControl object // with oid, 'false' and empty byte array LDAPControl ctrl = new LDAPControl(oid, false, new byte[0]); // add it to cList this.cList.add(ctrl); return null; // return value has no use } // get control criticality t = line.charAt(c); if( t == ' ') { // see a space, skip over any spaces while( (c <= lastChar) && (line.charAt(c) == ' ')) { c++; } } // what we see now? 'true', 'false', or ':' ? if(((c + 3) <= lastChar)&&(line.substring(c,c+4).equals("true"))) { // found 'true' c += 4; criticality = true; } else if(((c+4)<=lastChar)&&(line.substring(c,c+5).equals("false"))){ // found 'false' c += 5; criticality = false; } if (c > lastChar) { // to the end of the control field // create LDAPControl object with oid, // criticality, and empty byte array LDAPControl ctrl=new LDAPControl(oid, criticality, new byte[0]); // add it to cList this.cList.add(ctrl); return null; } if ((t=line.charAt(c)) != ':') { throw new LDAPLocalException("com.novell.ldap.ldif_dsml." + "LDIFReader: Unexcepted char '" + t + "'. Expecting " + "to see ':' in the record starting on line " + this.dnlNumber + " of the file.", LDAPException.LOCAL_ERROR); } // get control value c++; // go to enst char after ':' if (c > lastChar) { throw new LDAPLocalException("com.novell.ldap.ldif_dsml." + "LDIFReader: No control value after ':' " + "in the record starting on line " + this.dnlNumber + " of the file.", LDAPException.LOCAL_ERROR); } // positioned at the first char right after ':' // check if '::' or ':<' t = line.charAt(c); if( t == ':') { isEncoded = true; // indicate encoded value c++; // point to value if (c > lastChar) { throw new LDAPLocalException("com.novell.ldap.ldif_dsml." + "LDIFReader: No control value after '::' " + "in the record starting on line " + this.dnlNumber + " of the file.", LDAPException.LOCAL_ERROR); } } else if( t == '<') { isURL = true; // indicate file URL value c++; // point to value if (c > lastChar) { throw new LDAPLocalException("com.novell.ldap.ldif_dsml." + "LDIFReader: No control value after ':<' " + "in the record starting on line " + this.dnlNumber + " of the file.", LDAPException.LOCAL_ERROR); } } // eliminate any space(s) after ':', '::' or ':<' while((c <= lastChar) && (line.charAt(c) == ' ')) { c++; } if(c <= lastChar) { // thers is a value spec specified char[] chars = new char[lastChar+1-c]; line.getChars(c, lastChar+1, chars, 0); if (isEncoded) { this.bytes = Base64.decode(chars); } else if (isURL) { // if isURL, what to do? this.bytes = (new String(chars)).getBytes(); } else { this.bytes = (new String(chars)).getBytes(); } } // create LDAPControl object LDAPControl ctrl = new LDAPControl(oid, criticality, this.bytes); // add it to cList this.cList.add(ctrl); } return null; } }
这样的好处是不用在ldif文件中添加 “version:1” “changetype:add”
dn:: Yz3kuK3ljY7kurrmsJHlhbHlkozlm70=
objectClass: top
objectClass: country
c:: 5Lit5Y2O5Lq65rCR5YWx5ZKM5Zu9
dn:: bz3lm5vlt50sIGM95Lit5Y2O5Lq65rCR5YWx5ZKM5Zu9
objectClass: top
objectClass: organization
o:: 5Zub5bed
dn:: bz3miJDpg70sbz3lm5vlt50sIGM95Lit5Y2O5Lq65rCR5YWx5ZKM5Zu9
objectClass: top
objectClass: organization
o:: 5oiQ6YO9
运行后,刷新根节点