blob: 4b29c0f806ed2ef66d6d0ead93033244cc8917bf [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.directory.server.ldap.replication;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.directory.api.ldap.model.constants.SchemaConstants;
import org.apache.directory.api.ldap.model.cursor.EntryCursor;
import org.apache.directory.api.ldap.model.entry.DefaultEntry;
import org.apache.directory.api.ldap.model.entry.Entry;
import org.apache.directory.api.ldap.model.message.DeleteRequest;
import org.apache.directory.api.ldap.model.message.DeleteRequestImpl;
import org.apache.directory.api.ldap.model.message.DeleteResponse;
import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
import org.apache.directory.api.ldap.model.message.ModifyDnRequestImpl;
import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
import org.apache.directory.api.ldap.model.message.ModifyRequest;
import org.apache.directory.api.ldap.model.message.ModifyRequestImpl;
import org.apache.directory.api.ldap.model.message.ModifyResponse;
import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
import org.apache.directory.api.ldap.model.message.SearchScope;
import org.apache.directory.api.ldap.model.name.Dn;
import org.apache.directory.api.ldap.model.name.Rdn;
import org.apache.directory.api.ldap.model.url.LdapUrl;
import org.apache.directory.ldap.client.api.LdapConnection;
import org.apache.directory.ldap.client.api.LdapNetworkConnection;
import org.apache.directory.server.annotations.CreateConsumer;
import org.apache.directory.server.annotations.CreateLdapServer;
import org.apache.directory.server.annotations.CreateTransport;
import org.apache.directory.server.constants.ServerDNConstants;
import org.apache.directory.server.core.annotations.CreateDS;
import org.apache.directory.server.core.annotations.CreateIndex;
import org.apache.directory.server.core.annotations.CreatePartition;
import org.apache.directory.server.core.api.CoreSession;
import org.apache.directory.server.core.api.DirectoryService;
import org.apache.directory.server.core.factory.DSAnnotationProcessor;
import org.apache.directory.server.core.factory.MavibotPartitionFactory;
import org.apache.directory.server.core.integ.FrameworkRunner;
import org.apache.directory.server.factory.ServerAnnotationProcessor;
import org.apache.directory.server.ldap.LdapServer;
import org.apache.directory.server.ldap.replication.consumer.ReplicationConsumer;
import org.apache.directory.server.ldap.replication.consumer.ReplicationConsumerImpl;
import org.apache.directory.server.ldap.replication.provider.SyncReplRequestHandler;
/**
* Holds the configuration and instances of connections
*
* WARN: this class is not yet ready to run as a junit test cause it requires
* some manual setup of servers and test is invoked by main()
* The existing annotation based server instances are not used yet.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class MmrTester
{
// replicate a branch under partition instead of partition
// this will enable to us to test the case where a entry was
// moved out of replication area
private static final String REPL_AREA_SUFFIX = "ou=replicationarea,dc=example,dc=com";
private static final String RDN_PREFIX = "p";
private Set<String> urls = new LinkedHashSet<String>();
private List<LdapNetworkConnection> connections;
private static final int TOTAL_ENTRY_COUNT = 200;
private AtomicInteger count = new AtomicInteger(-1);
private Random rand = new Random();
private boolean verbose = false;
private static LdapServer peer1Server;
private static LdapServer peer2Server;
public MmrTester( String... ldapUrls )
{
if( ( ldapUrls == null ) || ( ldapUrls.length < 2 ) )
{
throw new IllegalArgumentException( "Atleast two servers are required to run MMR tests" );
}
for( String u : ldapUrls )
{
urls.add( u.toLowerCase() );
}
}
public void prepareConnections() throws Exception
{
connections = new ArrayList<LdapNetworkConnection>();
for( String u : urls )
{
LdapUrl url = new LdapUrl( u );
boolean useSsl = false;
if( url.getScheme().equals( "ldaps" ) )
{
useSsl = true;
}
LdapNetworkConnection c = new LdapNetworkConnection( url.getHost(), url.getPort(), useSsl );
c.setTimeOut( Long.MAX_VALUE );
c.connect();
c.bind( ServerDNConstants.ADMIN_SYSTEM_DN, "secret" );
System.out.println( "connected to the server " + url );
connections.add( c );
}
}
public void addAndCompare()
{
List<Dn> injected = new ArrayList<Dn>();
int batch = 20;
if( batch > TOTAL_ENTRY_COUNT )
{
batch = TOTAL_ENTRY_COUNT;
}
else
{
batch = TOTAL_ENTRY_COUNT;
}
for( int i=0; i < batch; i++ )
{
int index = rand.nextInt( connections.size() );
LdapNetworkConnection nc = connections.get( index );
if( verbose )
{
System.out.println( "inserting into the server " + nc.getConfig().getLdapHost() + ":" + nc.getConfig().getLdapPort() );
}
Entry e = createEntry( count.incrementAndGet() );
if ( inject( nc, e ) )
{
injected.add( e.getDn() );
}
}
compareEntries( injected );
}
public List<Dn> modify() throws Exception
{
List<Dn> modified = new ArrayList<Dn>();
int batch = 20;
if( batch > TOTAL_ENTRY_COUNT )
{
batch = TOTAL_ENTRY_COUNT;
}
else
{
batch = (int) ( TOTAL_ENTRY_COUNT * 0.10 ); // modify 10% of total entries
}
for( int i=0; i < batch; i++ )
{
int connectionIndex = rand.nextInt( connections.size() );
int entryIndex = rand.nextInt( batch );
LdapNetworkConnection nc = connections.get( connectionIndex );
String cn = RDN_PREFIX + entryIndex;
Dn personDn = new Dn( "cn=" + cn + "," + REPL_AREA_SUFFIX );
if ( verbose )
{
System.out.println( "modifying " + personDn + " on the server " + nc.getConfig().getLdapHost() + ":" + nc.getConfig().getLdapPort() );
}
ModifyRequest modReq = new ModifyRequestImpl();
modReq.setName( personDn );
modReq.replace( SchemaConstants.SN_AT, "sn_" + i );
ModifyResponse resp = nc.modify( modReq );
ResultCodeEnum rc = resp.getLdapResult().getResultCode();
if( rc != ResultCodeEnum.SUCCESS )
{
System.out.println( "Error modifying " + personDn + " on the server " + nc.getConfig().getLdapHost() + ":" + nc.getConfig().getLdapPort() + " with result code " + rc );
}
modified.add( personDn );
}
return modified;
}
public void moveAndCompare( Dn superiorDn ) throws Exception
{
List<Dn> moved = new ArrayList<Dn>();
int batch = 5;
if( batch > TOTAL_ENTRY_COUNT )
{
batch = TOTAL_ENTRY_COUNT;
}
else
{
batch = (int) ( TOTAL_ENTRY_COUNT * 0.20 ); // move 20% of total entries
}
for( int i=0; i < batch; i++ )
{
int connectionIndex = rand.nextInt( connections.size() );
LdapNetworkConnection nc = connections.get( connectionIndex );
String cn = RDN_PREFIX + i;
Dn personDn = new Dn( "cn=" + cn + "," + REPL_AREA_SUFFIX );
if( verbose )
{
System.out.println( "moving " + personDn + " on the server " + nc.getConfig().getLdapHost() + ":" + nc.getConfig().getLdapPort() + ":" + nc.getConfig().getLdapPort() );
}
ModifyDnRequest modReq = new ModifyDnRequestImpl();
modReq.setName( personDn );
modReq.setNewRdn( personDn.getRdn() );
modReq.setNewSuperior( superiorDn );
ModifyDnResponse resp = nc.modifyDn( modReq );
ResultCodeEnum rc = resp.getLdapResult().getResultCode();
if( rc != ResultCodeEnum.SUCCESS )
{
System.out.println( "Error moving " + personDn + " on the server " + nc.getConfig().getLdapHost() + ":" + nc.getConfig().getLdapPort() + ":" + nc.getConfig().getLdapPort() + " with result code " + rc );
}
moved.add( superiorDn.add( personDn.getRdn() ) );
}
compareEntries( moved );
}
public List<Dn> renameAndCompare( Dn containerDn ) throws Exception
{
List<Dn> renamed = new ArrayList<Dn>();
List<Dn> present = new ArrayList<Dn>();
int connectionIndex = rand.nextInt( connections.size() );
LdapNetworkConnection nc = connections.get( connectionIndex );
EntryCursor cursor = nc.search( containerDn, "(cn=" + RDN_PREFIX + "*)", SearchScope.ONELEVEL, SchemaConstants.NO_ATTRIBUTE_ARRAY );
while( cursor.next() )
{
present.add( cursor.get().getDn() );
}
cursor.close();
for( int i=0; i < present.size(); i++ )
{
connectionIndex = rand.nextInt( connections.size() );
nc = connections.get( connectionIndex );
Dn personDn = present.get( i );
ModifyDnRequest modReq = new ModifyDnRequestImpl();
Rdn newRdn = new Rdn( "cn=p_rename" + i );
modReq.setName( personDn );
modReq.setNewRdn( newRdn );
if( verbose )
{
System.out.println( "renaming " + personDn + " on the server " + nc.getConfig().getLdapHost() + ":" + nc.getConfig().getLdapPort() );
}
ModifyDnResponse resp = nc.modifyDn( modReq );
ResultCodeEnum rc = resp.getLdapResult().getResultCode();
if( rc != ResultCodeEnum.SUCCESS )
{
System.out.println( "Error renaming " + personDn + " on the server " + nc.getConfig().getLdapHost() + ":" + nc.getConfig().getLdapPort() + " with result code " + rc );
}
renamed.add( personDn.getParent().add( newRdn ) );
}
compareEntries( renamed );
return renamed;
}
public void deleteAndVerify( List<Dn> present ) throws Exception
{
List<Dn> deleted = new ArrayList<Dn>();
int count = present.size();//( present.size() - 2 );
for( int i=0; i < count; i++ )
{
int connectionIndex = rand.nextInt( connections.size() );
LdapNetworkConnection nc = connections.get( connectionIndex );
Dn personDn = present.get( i );
DeleteRequest delReq = new DeleteRequestImpl();
delReq.setName( personDn );
if( verbose )
{
System.out.println( "deleting " + personDn + " on the server " + nc.getConfig().getLdapHost() + ":" + nc.getConfig().getLdapPort() );
}
DeleteResponse resp = nc.delete( delReq );
ResultCodeEnum rc = resp.getLdapResult().getResultCode();
if( rc != ResultCodeEnum.SUCCESS )
{
System.out.println( "Error deleting " + personDn + " on the server " + nc.getConfig().getLdapHost() + ":" + nc.getConfig().getLdapPort() + " with result code " + rc );
}
deleted.add( personDn );
}
verifyDeleted( deleted );
}
public void moveOutOfReplAreaAndCompare() throws Exception
{
Dn parentDn = new Dn( "ou=parent,ou=children,ou=grandchildren");
Dn currentDn = new Dn( REPL_AREA_SUFFIX );
LdapNetworkConnection nc = connections.get( 0 );
for( Rdn rdn : parentDn.getRdns() )
{
currentDn = new Dn( rdn.getName() + "," + currentDn.getName() );
Entry e = new DefaultEntry( currentDn.getName(),
"objectclass: top",
"objectclass: organizationalUnit",
"ou: " + rdn.getAva().getValue().getString() );
nc.add( e );
}
compareEntries( Collections.singletonList( currentDn ) );
Dn ouDn = currentDn.getParent().getParent();
if( verbose )
{
System.out.println( "moving " + ouDn + " on the server " + nc.getConfig().getLdapHost() + ":" + nc.getConfig().getLdapPort() + ":" + nc.getConfig().getLdapPort() );
}
ModifyDnRequest modReq = new ModifyDnRequestImpl();
modReq.setName( ouDn );
modReq.setNewRdn( ouDn.getRdn() );
modReq.setNewSuperior( ouDn.getParent().getParent() );
ModifyDnResponse resp = nc.modifyDn( modReq );
ResultCodeEnum rc = resp.getLdapResult().getResultCode();
if( rc != ResultCodeEnum.SUCCESS )
{
System.out.println( "Error moving " + ouDn + " on the server " + nc.getConfig().getLdapHost() + ":" + nc.getConfig().getLdapPort() + ":" + nc.getConfig().getLdapPort() + " with result code " + rc );
}
Thread.sleep( 2000 );
verifyDeleted( Collections.singletonList( ouDn ) );
}
public void compareEntries( List<Dn> injected )
{
for( Dn dn : injected )
{
Entry baseEntry = null;
Iterator<LdapNetworkConnection> itr = connections.iterator();
LdapNetworkConnection c = itr.next();
baseEntry = lookupWithWait( c, dn );
while( itr.hasNext() )
{
c = itr.next();
Entry replicaEntry = lookupWithWait( c, dn );
boolean equal = baseEntry.equals( replicaEntry );
if( !equal )
{
System.out.println( "base entry: " + baseEntry );
System.out.println( "replica entry: " + replicaEntry );
}
assertTrue( equal );
}
}
}
public void verifyDeleted( List<Dn> injected )
{
for( Dn dn : injected )
{
Iterator<LdapNetworkConnection> itr = connections.iterator();
outer: while( itr.hasNext() )
{
LdapNetworkConnection c = itr.next();
try
{
for( int i = 1; i <= 10; i++ )
{
if( !c.exists( dn ) )
{
System.out.println( dn + " doesn't exist in the server " + c.getConfig().getLdapHost() + ":" + c.getConfig().getLdapPort() );
continue outer;
}
Thread.sleep( 1000 * i );
}
throw new RuntimeException( "deleted Entry " + dn + " found on server " + c.getConfig().getLdapHost() + ":" + c.getConfig().getLdapPort() );
}
catch( Exception e )
{
throw new RuntimeException( e );
}
}
}
}
public Entry lookupWithWait( LdapNetworkConnection c, Dn dn )
{
try
{
for( int i = 1; i <= 10; )
{
if( !c.exists( dn ) )
{
Thread.sleep( 1000 * i );
continue;
}
return c.lookup( dn, SchemaConstants.ALL_USER_ATTRIBUTES, SchemaConstants.ENTRY_UUID_AT );
}
}
catch( Exception e )
{
throw new RuntimeException( e );
}
throw new RuntimeException( "Entry " + dn + " not found on server " + c.getConfig().getLdapHost() + ":" + c.getConfig().getLdapPort() );
}
public boolean inject( LdapNetworkConnection nc, Entry e )
{
try
{
nc.add( e );
return true;
}
catch( Exception ex )
{
count.decrementAndGet();
ex.printStackTrace();
return false;
}
}
public boolean isCountReached()
{
return ( count.get() >= TOTAL_ENTRY_COUNT );
}
public void injectAndWaitTillReplicates( Entry ctxEntry ) throws Exception
{
LdapNetworkConnection c = connections.get( 0 );
if( !c.exists( ctxEntry.getDn() ) )
{
c.add( ctxEntry );
}
compareEntries( Collections.singletonList( ctxEntry.getDn() ) );
}
private Entry createEntry( int num )
{
try
{
String cn = RDN_PREFIX + num;
Dn personDn = new Dn( "cn=" + cn + "," + REPL_AREA_SUFFIX );
Entry person = new DefaultEntry(
personDn.toString(),
"ObjectClass: top",
"ObjectClass: person",
"cn: " + cn,
"sn: sn_" + cn,
"userPassword: 12345" );
return person;
}
catch( Exception e )
{
throw new RuntimeException( e );
}
}
public void closeConnections()
{
for( LdapNetworkConnection nc : connections )
{
try
{
nc.close();
}
catch( Exception e )
{
//ignore
e.printStackTrace();
}
}
}
public static void main( String[] args )
{
//System.setProperty( "apacheds.partition.factory", MavibotPartitionFactory.class.getName() );
MmrTester cc = new MmrTester( "ldap://localhost:16001", "ldap://localhost:16000" );
if( TOTAL_ENTRY_COUNT < 150 )
{
cc.verbose = true;
}
try
{
Thread t1 = new Thread( new Runnable()
{
@Override
public void run()
{
try
{
startPeer1();
}
catch(Exception e )
{
e.printStackTrace();
}
}
} );
t1.setDaemon( true );
Thread t2 = new Thread( new Runnable()
{
@Override
public void run()
{
try
{
startPeer2();
}
catch(Exception e )
{
e.printStackTrace();
}
}
} );
t2.setDaemon( true );
t1.start();
t2.start();
t1.join();
t2.join();
cc.prepareConnections();
Entry ctxEntry = new DefaultEntry( "dc=example,dc=com",
"objectClass: domain",
"objectClass: top",
"dc: example" );
for( LdapConnection lc : cc.connections )
{
lc.add( ctxEntry );
}
Entry replAreaEntry = new DefaultEntry( REPL_AREA_SUFFIX,
"objectClass: organizationalunit",
"ou: replicationarea" );
cc.injectAndWaitTillReplicates( replAreaEntry );
cc.moveOutOfReplAreaAndCompare();
cc.addAndCompare();
List<Dn> modified = cc.modify();
Thread.sleep( 15000 );
cc.compareEntries( modified );
Entry groupEntry = new DefaultEntry( "ou=groups," + REPL_AREA_SUFFIX,
"objectClass: organizationalUnit",
"objectClass: top",
"ou: groups" );
cc.injectAndWaitTillReplicates( groupEntry );
cc.moveAndCompare( groupEntry.getDn() );
List<Dn> renamed = cc.renameAndCompare( groupEntry.getDn() );
cc.deleteAndVerify( renamed );
}
catch( Exception e )
{
e.printStackTrace();
}
finally
{
cc.closeConnections();
shutdown();
}
}
@CreateDS(
allowAnonAccess = true,
enableChangeLog = false,
name = "peer1",
partitions =
{
@CreatePartition(
name = "example",
suffix = "dc=example,dc=com",
indexes =
{
@CreateIndex(attribute = "objectClass"),
@CreateIndex(attribute = "dc"),
@CreateIndex(attribute = "ou")
})
})
@CreateLdapServer(transports =
{ @CreateTransport(port = 16000, protocol = "LDAP") })
@CreateConsumer
(
remoteHost = "localhost",
remotePort = 16001,
replUserDn = "uid=admin,ou=system",
replUserPassword = "secret",
useTls = false,
baseDn = REPL_AREA_SUFFIX,
replicaId = 1,
refreshNPersist = true
)
public static void startPeer1() throws Exception
{
DirectoryService provDirService = DSAnnotationProcessor.getDirectoryService();
peer1Server = ServerAnnotationProcessor.getLdapServer( provDirService );
peer1Server.setReplicationReqHandler( new SyncReplRequestHandler() );
peer1Server.startReplicationProducer();
final ReplicationConsumerImpl consumer = ( ReplicationConsumerImpl ) ServerAnnotationProcessor.createConsumer();
List<ReplicationConsumer> replConsumers = new ArrayList<ReplicationConsumer>();
replConsumers.add( consumer );
peer1Server.setReplConsumers( replConsumers );
peer1Server.startReplicationConsumers();
Runnable r = new Runnable()
{
public void run()
{
try
{
DirectoryService ds = peer1Server.getDirectoryService();
System.out.println(ds.getInstanceLayout().getInstanceDirectory());
Dn configDn = new Dn( ds.getSchemaManager(), "ads-replConsumerId=localhost,ou=system" );
consumer.getConfig().setConfigEntryDn( configDn );
Entry provConfigEntry = new DefaultEntry( ds.getSchemaManager(), configDn,
"objectClass: ads-replConsumer",
"ads-replConsumerId: localhost",
"ads-searchBaseDN", consumer.getConfig().getBaseDn(),
"ads-replProvHostName", consumer.getConfig().getRemoteHost(),
"ads-replProvPort", String.valueOf( consumer.getConfig().getRemotePort() ),
"ads-replRefreshInterval", String.valueOf( consumer.getConfig().getRefreshInterval() ),
"ads-replRefreshNPersist", String.valueOf( consumer.getConfig().isRefreshNPersist() ),
"ads-replSearchScope", consumer.getConfig().getSearchScope().getLdapUrlValue(),
"ads-replSearchFilter", consumer.getConfig().getFilter(),
"ads-replSearchSizeLimit", String.valueOf( consumer.getConfig().getSearchSizeLimit() ),
"ads-replSearchTimeOut", String.valueOf( consumer.getConfig().getSearchTimeout() ),
"ads-replUserDn", consumer.getConfig().getReplUserDn(),
"ads-replUserPassword", consumer.getConfig().getReplUserPassword() );
provConfigEntry.put( "ads-replAliasDerefMode", consumer.getConfig().getAliasDerefMode()
.getJndiValue() );
provConfigEntry.put( "ads-replAttributes", consumer.getConfig().getAttributes() );
CoreSession consumerSession = peer1Server.getDirectoryService().getAdminSession();
consumerSession.add( provConfigEntry );
}
catch ( Exception e )
{
throw new RuntimeException( e );
}
}
};
Thread t = new Thread( r );
t.setDaemon( true );
t.start();
t.join();
}
@CreateDS(
allowAnonAccess = true,
enableChangeLog = false,
name = "peer2",
partitions =
{
@CreatePartition(
name = "example",
suffix = "dc=example,dc=com",
indexes =
{
@CreateIndex(attribute = "objectClass"),
@CreateIndex(attribute = "dc"),
@CreateIndex(attribute = "ou")
})
})
@CreateLdapServer(transports =
{ @CreateTransport(port = 16001, protocol = "LDAP") })
@CreateConsumer
(
remoteHost = "localhost",
remotePort = 16000,
replUserDn = "uid=admin,ou=system",
replUserPassword = "secret",
useTls = false,
baseDn = REPL_AREA_SUFFIX,
refreshNPersist = true,
replicaId = 1
)
public static void startPeer2() throws Exception
{
DirectoryService provDirService = DSAnnotationProcessor.getDirectoryService();
peer2Server = ServerAnnotationProcessor.getLdapServer( provDirService );
peer2Server.setReplicationReqHandler( new SyncReplRequestHandler() );
peer2Server.startReplicationProducer();
final ReplicationConsumerImpl consumer = ( ReplicationConsumerImpl ) ServerAnnotationProcessor.createConsumer();
List<ReplicationConsumer> replConsumers = new ArrayList<ReplicationConsumer>();
replConsumers.add( consumer );
peer2Server.setReplConsumers( replConsumers );
peer2Server.startReplicationConsumers();
Runnable r = new Runnable()
{
public void run()
{
try
{
DirectoryService ds = peer2Server.getDirectoryService();
Dn configDn = new Dn( ds.getSchemaManager(), "ads-replConsumerId=localhost,ou=system" );
consumer.getConfig().setConfigEntryDn( configDn );
Entry provConfigEntry = new DefaultEntry( ds.getSchemaManager(), configDn,
"objectClass: ads-replConsumer",
"ads-replConsumerId: localhost",
"ads-searchBaseDN", consumer.getConfig().getBaseDn(),
"ads-replProvHostName", consumer.getConfig().getRemoteHost(),
"ads-replProvPort", String.valueOf( consumer.getConfig().getRemotePort() ),
"ads-replRefreshInterval", String.valueOf( consumer.getConfig().getRefreshInterval() ),
"ads-replRefreshNPersist", String.valueOf( consumer.getConfig().isRefreshNPersist() ),
"ads-replSearchScope", consumer.getConfig().getSearchScope().getLdapUrlValue(),
"ads-replSearchFilter", consumer.getConfig().getFilter(),
"ads-replSearchSizeLimit", String.valueOf( consumer.getConfig().getSearchSizeLimit() ),
"ads-replSearchTimeOut", String.valueOf( consumer.getConfig().getSearchTimeout() ),
"ads-replUserDn", consumer.getConfig().getReplUserDn(),
"ads-replUserPassword", consumer.getConfig().getReplUserPassword() );
provConfigEntry.put( "ads-replAliasDerefMode", consumer.getConfig().getAliasDerefMode()
.getJndiValue() );
provConfigEntry.put( "ads-replAttributes", consumer.getConfig().getAttributes() );
CoreSession consumerSession = peer2Server.getDirectoryService().getAdminSession();
consumerSession.add( provConfigEntry );
}
catch ( Exception e )
{
throw new RuntimeException( e );
}
}
};
Thread t = new Thread( r );
t.setDaemon( true );
t.start();
t.join();
}
public static void shutdown()
{
peer1Server.stop();
peer2Server.stop();
}
}